QGIS API Documentation  2.14.0-Essen
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 "qgsrendererv2.h"
32 #include "qgssymbollayerv2utils.h"
33 #include "qgsvectorlayer.h"
34 
35 
37  : QAbstractItemModel( parent )
38  , mRootNode( rootNode )
39  , mFlags( ShowLegend | AllowLegendChangeState | DeferredLegendInvalidation )
40  , mAutoCollapseLegendNodesCount( -1 )
41  , mLegendFilterByScale( 0 )
42  , mLegendMapViewMupp( 0 )
43  , mLegendMapViewDpi( 0 )
44  , mLegendMapViewScale( 0 )
45 {
47 
48  mFontLayer.setBold( true );
49 
50  connect( &mDeferLegendInvalidationTimer, SIGNAL( timeout() ), this, SLOT( invalidateLegendMapBasedData() ) );
52 }
53 
55 {
56  legendCleanup();
57 }
58 
60 {
61  if ( !index.isValid() )
62  return mRootNode;
63 
64  QObject* obj = reinterpret_cast<QObject*>( index.internalPointer() );
65  return qobject_cast<QgsLayerTreeNode*>( obj );
66 }
67 
68 
70 {
71  if ( QgsLayerTreeModelLegendNode* nodeLegend = index2legendNode( parent ) )
72  return legendNodeRowCount( nodeLegend );
73 
74  QgsLayerTreeNode* n = index2node( parent );
75  if ( !n )
76  return 0;
77 
78  if ( QgsLayerTree::isLayer( n ) )
79  {
80  if ( !testFlag( ShowLegend ) )
81  return 0;
82 
84  }
85 
86  return n->children().count();
87 }
88 
90 {
91  Q_UNUSED( parent );
92  return 1;
93 }
94 
95 QModelIndex QgsLayerTreeModel::index( int row, int column, const QModelIndex &parent ) const
96 {
97  if ( column < 0 || column >= columnCount( parent ) ||
98  row < 0 || row >= rowCount( parent ) )
99  return QModelIndex();
100 
101  if ( QgsLayerTreeModelLegendNode* nodeLegend = index2legendNode( parent ) )
102  return legendNodeIndex( row, column, nodeLegend );
103 
104  QgsLayerTreeNode *n = index2node( parent );
105  if ( !n )
106  return QModelIndex(); // have no children
107 
108  if ( testFlag( ShowLegend ) && QgsLayerTree::isLayer( n ) )
109  {
110  return legendRootIndex( row, column, QgsLayerTree::toLayer( n ) );
111  }
112 
113  return createIndex( row, column, static_cast<QObject*>( n->children().at( row ) ) );
114 }
115 
116 
118 {
119  if ( !child.isValid() )
120  return QModelIndex();
121 
122  if ( QgsLayerTreeNode *n = index2node( child ) )
123  {
124  return indexOfParentLayerTreeNode( n->parent() ); // must not be null
125  }
126  else if ( QgsLayerTreeModelLegendNode* legendNode = index2legendNode( child ) )
127  {
128  return legendParent( legendNode );
129  }
130  else
131  {
132  Q_ASSERT( false ); // no other node types!
133  return QModelIndex();
134  }
135 
136 }
137 
138 
140 {
141  Q_ASSERT( parentNode );
142 
143  QgsLayerTreeNode* grandParentNode = parentNode->parent();
144  if ( !grandParentNode )
145  return QModelIndex(); // root node -> invalid index
146 
147  int row = grandParentNode->children().indexOf( parentNode );
148  Q_ASSERT( row >= 0 );
149 
150  return createIndex( row, 0, static_cast<QObject*>( parentNode ) );
151 }
152 
153 
155 {
156  if ( !index.isValid() || index.column() > 1 )
157  return QVariant();
158 
159  if ( QgsLayerTreeModelLegendNode* sym = index2legendNode( index ) )
160  return legendNodeData( sym, role );
161 
162  QgsLayerTreeNode* node = index2node( index );
163  if ( role == Qt::DisplayRole || role == Qt::EditRole )
164  {
165  if ( QgsLayerTree::isGroup( node ) )
166  return QgsLayerTree::toGroup( node )->name();
167 
168  if ( QgsLayerTree::isLayer( node ) )
169  {
170  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
171  QString name = nodeLayer->layerName();
172  if ( nodeLayer->customProperty( "showFeatureCount", 0 ).toInt() && role == Qt::DisplayRole )
173  {
174  QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( nodeLayer->layer() );
175  if ( vlayer && vlayer->featureCount() >= 0 )
176  name += QString( " [%1]" ).arg( vlayer->featureCount() );
177  }
178  return name;
179  }
180  }
181  else if ( role == Qt::DecorationRole && index.column() == 0 )
182  {
183  if ( QgsLayerTree::isGroup( node ) )
184  return iconGroup();
185 
186  if ( QgsLayerTree::isLayer( node ) )
187  {
188  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
189 
190  QgsMapLayer *layer = nodeLayer->layer();
191  if ( !layer )
192  return QVariant();
193 
194  // icons possibly overriding default icon
195  if ( layer->type() == QgsMapLayer::RasterLayer )
196  {
198  {
199  QgsRasterLayer* rlayer = qobject_cast<QgsRasterLayer *>( layer );
200  return QIcon( QPixmap::fromImage( rlayer->previewAsImage( QSize( 32, 32 ) ) ) );
201  }
202  else
203  {
204  return QgsLayerItem::iconRaster();
205  }
206  }
207 
208  QgsVectorLayer *vlayer = dynamic_cast<QgsVectorLayer*>( layer );
209  QIcon icon;
210 
211  // if there's just on legend entry that should be embedded in layer - do that!
212  if ( testFlag( ShowLegend ) && legendEmbeddedInParent( nodeLayer ) )
213  {
214  icon = legendIconEmbeddedInParent( nodeLayer );
215  }
216  else if ( vlayer && layer->type() == QgsMapLayer::VectorLayer )
217  {
218  if ( vlayer->geometryType() == QGis::Point )
219  icon = QgsLayerItem::iconPoint();
220  else if ( vlayer->geometryType() == QGis::Line )
221  icon = QgsLayerItem::iconLine();
222  else if ( vlayer->geometryType() == QGis::Polygon )
223  icon = QgsLayerItem::iconPolygon();
224  else if ( vlayer->geometryType() == QGis::NoGeometry )
225  icon = QgsLayerItem::iconTable();
226  else
227  icon = QgsLayerItem::iconDefault();
228  }
229 
230  if ( vlayer && vlayer->isEditable() )
231  {
232  QPixmap pixmap( icon.pixmap( 16, 16 ) );
233 
234  QPainter painter( &pixmap );
235  painter.drawPixmap( 0, 0, 16, 16, QgsApplication::getThemePixmap( vlayer->isModified() ? "/mIconEditableEdits.png" : "/mIconEditable.png" ) );
236  painter.end();
237 
238  icon = QIcon( pixmap );
239  }
240 
241  return icon;
242  }
243  }
244  else if ( role == Qt::CheckStateRole )
245  {
247  return QVariant();
248 
249  if ( QgsLayerTree::isLayer( node ) )
250  {
251  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
252  if ( nodeLayer->layer() && nodeLayer->layer()->type() == QgsMapLayer::VectorLayer )
253  {
254  if ( qobject_cast<QgsVectorLayer*>( nodeLayer->layer() )->geometryType() == QGis::NoGeometry )
255  return QVariant(); // do not show checkbox for non-spatial tables
256  }
257  return nodeLayer->isVisible();
258  }
259  else if ( QgsLayerTree::isGroup( node ) )
260  {
261  QgsLayerTreeGroup* nodeGroup = QgsLayerTree::toGroup( node );
262  return nodeGroup->isVisible();
263  }
264  }
265  else if ( role == Qt::FontRole )
266  {
267  QFont f( QgsLayerTree::isLayer( node ) ? mFontLayer : ( QgsLayerTree::isGroup( node ) ? mFontGroup : QFont() ) );
268  if ( node->customProperty( "embedded" ).toInt() )
269  f.setItalic( true );
270  if ( index == mCurrentIndex )
271  f.setUnderline( true );
272  return f;
273  }
274  else if ( role == Qt::ToolTipRole )
275  {
276  if ( QgsLayerTree::isLayer( node ) )
277  {
278  if ( QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer() )
279  return layer->publicSource();
280  }
281  }
282 
283  return QVariant();
284 }
285 
286 
288 {
289  if ( !index.isValid() )
290  {
291  Qt::ItemFlags rootFlags = nullptr;
292  if ( testFlag( AllowNodeReorder ) )
293  rootFlags |= Qt::ItemIsDropEnabled;
294  return rootFlags;
295  }
296 
297  if ( QgsLayerTreeModelLegendNode* symn = index2legendNode( index ) )
298  return legendNodeFlags( symn );
299 
300  Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
301 
302  if ( testFlag( AllowNodeRename ) )
303  f |= Qt::ItemIsEditable;
304 
305  QgsLayerTreeNode* node = index2node( index );
306  bool isEmbedded = node->customProperty( "embedded" ).toInt();
307 
308  if ( testFlag( AllowNodeReorder ) )
309  {
310  // only root embedded nodes can be reordered
311  if ( !isEmbedded || ( isEmbedded && node->parent() && !node->parent()->customProperty( "embedded" ).toInt() ) )
312  f |= Qt::ItemIsDragEnabled;
313  }
314 
316  f |= Qt::ItemIsUserCheckable;
317 
318  if ( testFlag( AllowNodeReorder ) && QgsLayerTree::isGroup( node ) && !isEmbedded )
319  f |= Qt::ItemIsDropEnabled;
320 
321  return f;
322 }
323 
324 bool QgsLayerTreeModel::setData( const QModelIndex& index, const QVariant& value, int role )
325 {
327  if ( sym )
328  {
329  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
330  return false;
331  bool res = sym->setData( value, role );
332  if ( res )
333  emit dataChanged( index, index );
334  return res;
335  }
336 
337  QgsLayerTreeNode* node = index2node( index );
338  if ( !node )
339  return QgsLayerTreeModel::setData( index, value, role );
340 
341  if ( role == Qt::CheckStateRole )
342  {
344  return false;
345 
346  if ( QgsLayerTree::isLayer( node ) )
347  {
348  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
349  layer->setVisible( static_cast< Qt::CheckState >( value.toInt() ) );
350  return true;
351  }
352 
353  if ( QgsLayerTree::isGroup( node ) )
354  {
355  QgsLayerTreeGroup* group = QgsLayerTree::toGroup( node );
356  group->setVisible( static_cast< Qt::CheckState >( value.toInt() ) );
357  return true;
358  }
359 
360  return true;
361  }
362  else if ( role == Qt::EditRole )
363  {
364  if ( !testFlag( AllowNodeRename ) )
365  return false;
366 
367  if ( QgsLayerTree::isLayer( node ) )
368  {
369  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
370  layer->setLayerName( value.toString() );
371  emit dataChanged( index, index );
372  }
373  else if ( QgsLayerTree::isGroup( node ) )
374  {
375  QgsLayerTree::toGroup( node )->setName( value.toString() );
376  emit dataChanged( index, index );
377  }
378  }
379 
380  return QAbstractItemModel::setData( index, value, role );
381 }
382 
384 {
385  if ( !node->parent() )
386  return QModelIndex(); // this is the only root item -> invalid index
387 
388  QModelIndex parentIndex = node2index( node->parent() );
389 
390  int row = node->parent()->children().indexOf( node );
391  Q_ASSERT( row >= 0 );
392  return index( row, 0, parentIndex );
393 }
394 
395 
397 {
398  if ( !child->parent() )
399  return false;
400 
401  if ( child->parent() == node )
402  return true;
403 
404  return _isChildOfNode( child->parent(), node );
405 }
406 
408 {
409  Q_FOREACH ( QgsLayerTreeNode* n, nodes )
410  {
411  if ( _isChildOfNode( child, n ) )
412  return true;
413  }
414 
415  return false;
416 }
417 
418 
419 QList<QgsLayerTreeNode*> QgsLayerTreeModel::indexes2nodes( const QModelIndexList& list, bool skipInternal ) const
420 {
422  Q_FOREACH ( const QModelIndex& index, list )
423  {
424  QgsLayerTreeNode* node = index2node( index );
425  if ( !node )
426  continue;
427 
428  nodes << node;
429  }
430 
431  if ( !skipInternal )
432  return nodes;
433 
434  // remove any children of nodes if both parent node and children are selected
435  QList<QgsLayerTreeNode*> nodesFinal;
436  Q_FOREACH ( QgsLayerTreeNode* node, nodes )
437  {
438  if ( !_isChildOfNodes( node, nodes ) )
439  nodesFinal << node;
440  }
441 
442  return nodesFinal;
443 }
444 
446 {
447  return nullptr != index2legendNode( index );
448 }
449 
451 {
452  QgsLayerTreeModelLegendNode* symNode = index2legendNode( index );
453  return symNode ? symNode->layerNode() : nullptr;
454 }
455 
457 {
458  return mRootNode;
459 }
460 
462 {
463  beginResetModel();
464 
466 
467  Q_ASSERT( mLegend.isEmpty() );
468 
469  mRootNode = newRootGroup;
470 
471  endResetModel();
472 
474 }
475 
477 {
478  // update title
479  QModelIndex idx = node2index( nodeLayer );
480  emit dataChanged( idx, idx );
481 
482  // update children
483  int oldNodeCount = rowCount( idx );
484  beginRemoveRows( idx, 0, oldNodeCount - 1 );
485  removeLegendFromLayer( nodeLayer );
486  endRemoveRows();
487 
488  addLegendToLayer( nodeLayer );
489  int newNodeCount = rowCount( idx );
490 
491  // automatic collapse of legend nodes - useful if a layer has many legend nodes
492  if ( mAutoCollapseLegendNodesCount != -1 && oldNodeCount != newNodeCount && newNodeCount >= mAutoCollapseLegendNodesCount )
493  nodeLayer->setExpanded( false );
494 }
495 
497 {
498  return mCurrentIndex;
499 }
500 
502 {
503  QModelIndex oldIndex = mCurrentIndex;
505 
506  if ( oldIndex.isValid() )
507  emit dataChanged( oldIndex, oldIndex );
508  if ( currentIndex.isValid() )
509  emit dataChanged( currentIndex, currentIndex );
510 }
511 
512 
513 void QgsLayerTreeModel::setLayerTreeNodeFont( int nodeType, const QFont& font )
514 {
515  if ( nodeType == QgsLayerTreeNode::NodeGroup )
516  {
517  if ( mFontGroup != font )
518  {
519  mFontGroup = font;
521  }
522  }
523  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
524  {
525  if ( mFontLayer != font )
526  {
527  mFontLayer = font;
529  }
530  }
531  else
532  {
533  QgsDebugMsg( "invalid node type" );
534  }
535 }
536 
537 
539 {
540  if ( nodeType == QgsLayerTreeNode::NodeGroup )
541  return mFontGroup;
542  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
543  return mFontLayer;
544  else
545  {
546  QgsDebugMsg( "invalid node type" );
547  return QFont();
548  }
549 }
550 
551 void QgsLayerTreeModel::setLegendFilterByScale( double scaleDenominator )
552 {
553  mLegendFilterByScale = scaleDenominator;
554 
555  // this could be later done in more efficient way
556  // by just updating active legend nodes, without refreshing original legend nodes
557  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
558  refreshLayerLegend( nodeLayer );
559 }
560 
562 {
563  setLegendFilter( settings, /* useExtent = */ true );
564 }
565 
566 void QgsLayerTreeModel::setLegendFilter( const QgsMapSettings* settings, bool useExtent, const QgsGeometry& polygon, bool useExpressions )
567 {
568  if ( settings && settings->hasValidSettings() )
569  {
570  mLegendFilterMapSettings.reset( new QgsMapSettings( *settings ) );
571  mLegendFilterMapSettings->setLayerStyleOverrides( mLayerStyleOverrides );
573  // collect expression filters
574  if ( useExpressions )
575  {
576  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
577  {
578  bool enabled;
579  QString expr = QgsLayerTreeUtils::legendFilterByExpression( *nodeLayer, &enabled );
580  if ( enabled && !expr.isEmpty() )
581  {
582  exprs[ nodeLayer->layerId()] = expr;
583  }
584  }
585  }
586  bool polygonValid = !polygon.isEmpty() && polygon.type() == QGis::Polygon;
587  if ( useExpressions && !useExtent && !polygonValid ) // only expressions
588  {
590  }
591  else
592  {
594  }
595  mLegendFilterHitTest->run();
596  }
597  else
598  {
600  return; // no change
601 
604  }
605 
606  // temporarily disable autocollapse so that legend nodes stay visible
607  int bkAutoCollapse = autoCollapseLegendNodes();
609 
610  // this could be later done in more efficient way
611  // by just updating active legend nodes, without refreshing original legend nodes
612  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
613  refreshLayerLegend( nodeLayer );
614 
615  setAutoCollapseLegendNodes( bkAutoCollapse );
616 }
617 
618 void QgsLayerTreeModel::setLegendMapViewData( double mapUnitsPerPixel, int dpi, double scale )
619 {
620  if ( mLegendMapViewDpi == dpi && qgsDoubleNear( mLegendMapViewMupp, mapUnitsPerPixel ) && qgsDoubleNear( mLegendMapViewScale, scale ) )
621  return;
622 
623  mLegendMapViewMupp = mapUnitsPerPixel;
624  mLegendMapViewDpi = dpi;
625  mLegendMapViewScale = scale;
626 
627  // now invalidate legend nodes!
629 }
630 
631 void QgsLayerTreeModel::legendMapViewData( double* mapUnitsPerPixel, int* dpi, double* scale )
632 {
633  if ( mapUnitsPerPixel ) *mapUnitsPerPixel = mLegendMapViewMupp;
634  if ( dpi ) *dpi = mLegendMapViewDpi;
635  if ( scale ) *scale = mLegendMapViewScale;
636 }
637 
639 {
640  return mLayerStyleOverrides;
641 }
642 
644 {
645  mLayerStyleOverrides = overrides;
646 }
647 
648 void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
649 {
650  Q_ASSERT( node );
651  beginInsertRows( node2index( node ), indexFrom, indexTo );
652 }
653 
654 static QList<QgsLayerTreeLayer*> _layerNodesInSubtree( QgsLayerTreeNode* node, int indexFrom, int indexTo )
655 {
657  QList<QgsLayerTreeLayer*> newLayerNodes;
658  for ( int i = indexFrom; i <= indexTo; ++i )
659  {
660  QgsLayerTreeNode* child = children.at( i );
661  if ( QgsLayerTree::isLayer( child ) )
662  newLayerNodes << QgsLayerTree::toLayer( child );
663  else if ( QgsLayerTree::isGroup( child ) )
664  newLayerNodes << QgsLayerTree::toGroup( child )->findLayers();
665  }
666  return newLayerNodes;
667 }
668 
669 void QgsLayerTreeModel::nodeAddedChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
670 {
671  Q_ASSERT( node );
672 
673  endInsertRows();
674 
675  Q_FOREACH ( QgsLayerTreeLayer* newLayerNode, _layerNodesInSubtree( node, indexFrom, indexTo ) )
676  connectToLayer( newLayerNode );
677 }
678 
679 void QgsLayerTreeModel::nodeWillRemoveChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
680 {
681  Q_ASSERT( node );
682 
683  beginRemoveRows( node2index( node ), indexFrom, indexTo );
684 
685  // disconnect from layers and remove their legend
686  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, _layerNodesInSubtree( node, indexFrom, indexTo ) )
687  disconnectFromLayer( nodeLayer );
688 }
689 
691 {
692  endRemoveRows();
693 }
694 
696 {
697  Q_ASSERT( node );
698 
699  QModelIndex index = node2index( node );
700  emit dataChanged( index, index );
701 }
702 
703 
705 {
706  if ( QgsLayerTree::isLayer( node ) && key == "showFeatureCount" )
708 }
709 
710 
712 {
713  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
714  if ( !nodeLayer )
715  return;
716 
717  // deferred connection to the layer
718  connectToLayer( nodeLayer );
719 }
720 
722 {
723  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
724  if ( !nodeLayer )
725  return;
726 
727  disconnectFromLayer( nodeLayer );
728 
729  // wait for the layer to appear again
730  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
731 }
732 
734 {
735  if ( !testFlag( ShowLegend ) )
736  return;
737 
738  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
739  if ( !layer )
740  return;
741 
742  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
743  if ( !nodeLayer )
744  return;
745 
746  refreshLayerLegend( nodeLayer );
747 }
748 
750 {
751  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
752  if ( !layer )
753  return;
754 
755  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
756  if ( !nodeLayer )
757  return;
758 
759  QModelIndex index = node2index( nodeLayer );
760  emit dataChanged( index, index );
761 
762  if ( nodeLayer->customProperty( "showFeatureCount" ).toInt() )
763  refreshLayerLegend( nodeLayer );
764 }
765 
766 
768 {
769  QgsLayerTreeModelLegendNode* legendNode = qobject_cast<QgsLayerTreeModelLegendNode*>( sender() );
770  if ( !legendNode )
771  return;
772 
773  QModelIndex index = legendNode2index( legendNode );
774  if ( index.isValid() )
775  emit dataChanged( index, index );
776 }
777 
778 
780 {
781  if ( !nodeLayer->layer() )
782  {
783  // in order to connect to layer, we need to have it loaded.
784  // keep an eye on the layer ID: once loaded, we will use it
785  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
786  return;
787  }
788 
789  // watch if the layer is getting removed
790  connect( nodeLayer, SIGNAL( layerWillBeUnloaded() ), this, SLOT( nodeLayerWillBeUnloaded() ) );
791 
792  if ( testFlag( ShowLegend ) )
793  {
794  addLegendToLayer( nodeLayer );
795 
796  // automatic collapse of legend nodes - useful if a layer has many legend nodes
797  if ( !mRootNode->customProperty( "loading" ).toBool() )
798  {
800  nodeLayer->setExpanded( false );
801  }
802  }
803 
804  QgsMapLayer* layer = nodeLayer->layer();
805  connect( layer, SIGNAL( legendChanged() ), this, SLOT( layerLegendChanged() ), Qt::UniqueConnection );
806 
807  if ( layer->type() == QgsMapLayer::VectorLayer )
808  {
809  // using unique connection because there may be temporarily more nodes for a layer than just one
810  // which would create multiple connections, however disconnect() would disconnect all multiple connections
811  // even if we wanted to disconnect just one connection in each call.
812  connect( layer, SIGNAL( editingStarted() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
813  connect( layer, SIGNAL( editingStopped() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
814  connect( layer, SIGNAL( layerModified() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
815  connect( layer, SIGNAL( layerNameChanged() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
816  }
817 }
818 
819 // try to find out if the layer ID is present in the tree multiple times
820 static int _numLayerCount( QgsLayerTreeGroup* group, const QString& layerId )
821 {
822  int count = 0;
823  Q_FOREACH ( QgsLayerTreeNode* child, group->children() )
824  {
825  if ( QgsLayerTree::isLayer( child ) )
826  {
827  if ( QgsLayerTree::toLayer( child )->layerId() == layerId )
828  count++;
829  }
830  else if ( QgsLayerTree::isGroup( child ) )
831  {
832  count += _numLayerCount( QgsLayerTree::toGroup( child ), layerId );
833  }
834  }
835  return count;
836 }
837 
839 {
840  disconnect( nodeLayer, nullptr, this, nullptr ); // disconnect from delayed load of layer
841 
842  if ( !nodeLayer->layer() )
843  return; // we were never connected
844 
845  if ( testFlag( ShowLegend ) )
846  {
847  removeLegendFromLayer( nodeLayer );
848  }
849 
850  if ( _numLayerCount( mRootNode, nodeLayer->layerId() ) == 1 )
851  {
852  // last instance of the layer in the tree: disconnect from all signals from layer!
853  disconnect( nodeLayer->layer(), nullptr, this, nullptr );
854  }
855 }
856 
858 {
859  Q_FOREACH ( QgsLayerTreeNode* node, parentGroup->children() )
860  {
861  if ( QgsLayerTree::isGroup( node ) )
863  else if ( QgsLayerTree::isLayer( node ) )
865  }
866 }
867 
869 {
870  Q_FOREACH ( QgsLayerTreeNode* node, parentGroup->children() )
871  {
872  if ( QgsLayerTree::isGroup( node ) )
874  else if ( QgsLayerTree::isLayer( node ) )
876  }
877 }
878 
880 {
881  Q_ASSERT( mRootNode );
882 
883  connect( mRootNode, SIGNAL( willAddChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillAddChildren( QgsLayerTreeNode*, int, int ) ) );
884  connect( mRootNode, SIGNAL( addedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeAddedChildren( QgsLayerTreeNode*, int, int ) ) );
885  connect( mRootNode, SIGNAL( willRemoveChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillRemoveChildren( QgsLayerTreeNode*, int, int ) ) );
886  connect( mRootNode, SIGNAL( removedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeRemovedChildren() ) );
887  connect( mRootNode, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
888 
889  connect( mRootNode, SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ), this, SLOT( nodeCustomPropertyChanged( QgsLayerTreeNode*, QString ) ) );
890 
892 }
893 
895 {
896  disconnect( mRootNode, nullptr, this, nullptr );
897 
899 }
900 
902 {
903  QgsLayerTreeNode* node = index2node( idx );
904  if ( !node )
905  return;
906 
907  int count = node->children().count();
908  if ( count == 0 )
909  return;
910  emit dataChanged( index( 0, 0, idx ), index( count - 1, 0, idx ) );
911  for ( int i = 0; i < count; ++i )
912  recursivelyEmitDataChanged( index( i, 0, idx ) );
913 }
914 
915 
917 {
918  return Qt::CopyAction | Qt::MoveAction;
919 }
920 
922 {
923  QStringList types;
924  types << "application/qgis.layertreemodeldata";
925  return types;
926 }
927 
928 
929 QMimeData* QgsLayerTreeModel::mimeData( const QModelIndexList& indexes ) const
930 {
931  // Sort the indexes. Depending on how the user selected the items, the indexes may be unsorted.
932  QModelIndexList sortedIndexes = indexes;
933  qSort( sortedIndexes.begin(), sortedIndexes.end(), qLess<QModelIndex>() );
934 
935  QList<QgsLayerTreeNode*> nodesFinal = indexes2nodes( sortedIndexes, true );
936 
937  if ( nodesFinal.isEmpty() )
938  return nullptr;
939 
940  QMimeData *mimeData = new QMimeData();
941 
942  QDomDocument doc;
943  QDomElement rootElem = doc.createElement( "layer_tree_model_data" );
944  Q_FOREACH ( QgsLayerTreeNode* node, nodesFinal )
945  node->writeXML( rootElem );
946  doc.appendChild( rootElem );
947  QString txt = doc.toString();
948 
949  mimeData->setData( "application/qgis.layertreemodeldata", txt.toUtf8() );
950  return mimeData;
951 }
952 
953 bool QgsLayerTreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
954 {
955  if ( action == Qt::IgnoreAction )
956  return true;
957 
958  if ( !data->hasFormat( "application/qgis.layertreemodeldata" ) )
959  return false;
960 
961  if ( column >= columnCount( parent ) )
962  return false;
963 
964  QgsLayerTreeNode* nodeParent = index2node( parent );
965  if ( !QgsLayerTree::isGroup( nodeParent ) )
966  return false;
967 
968  QByteArray encodedData = data->data( "application/qgis.layertreemodeldata" );
969 
970  QDomDocument doc;
971  if ( !doc.setContent( QString::fromUtf8( encodedData ) ) )
972  return false;
973 
974  QDomElement rootElem = doc.documentElement();
975  if ( rootElem.tagName() != "layer_tree_model_data" )
976  return false;
977 
979 
980  QDomElement elem = rootElem.firstChildElement();
981  while ( !elem.isNull() )
982  {
984  if ( node )
985  nodes << node;
986 
987  elem = elem.nextSiblingElement();
988  }
989 
990  if ( nodes.isEmpty() )
991  return false;
992 
993  if ( parent.isValid() && row == -1 )
994  row = 0; // if dropped directly onto group item, insert at first position
995 
996  QgsLayerTree::toGroup( nodeParent )->insertChildNodes( row, nodes );
997 
998  return true;
999 }
1000 
1001 bool QgsLayerTreeModel::removeRows( int row, int count, const QModelIndex& parent )
1002 {
1003  QgsLayerTreeNode* parentNode = index2node( parent );
1004  if ( QgsLayerTree::isGroup( parentNode ) )
1005  {
1006  QgsLayerTree::toGroup( parentNode )->removeChildren( row, count );
1007  return true;
1008  }
1009  return false;
1010 }
1011 
1012 void QgsLayerTreeModel::setFlags( const QgsLayerTreeModel::Flags& f )
1013 {
1014  mFlags = f;
1015 }
1016 
1018 {
1019  if ( on )
1020  mFlags |= f;
1021  else
1022  mFlags &= ~f;
1023 }
1024 
1025 QgsLayerTreeModel::Flags QgsLayerTreeModel::flags() const
1026 {
1027  return mFlags;
1028 }
1029 
1031 {
1032  return mFlags.testFlag( f );
1033 }
1034 
1036 {
1037  static QIcon icon;
1038 
1039  if ( icon.isNull() )
1040  icon = QgsApplication::getThemeIcon( "/mActionFolder.png" );
1041 
1042  return icon;
1043 }
1044 
1046 {
1048 
1049  if ( mLegendFilterByScale > 0 )
1050  {
1051  Q_FOREACH ( QgsLayerTreeModelLegendNode* node, nodes )
1052  {
1053  if ( node->isScaleOK( mLegendFilterByScale ) )
1054  filtered << node;
1055  }
1056  }
1057  else if ( mLegendFilterMapSettings )
1058  {
1059  Q_FOREACH ( QgsLayerTreeModelLegendNode* node, nodes )
1060  {
1061  QgsSymbolV2* symbolKey = reinterpret_cast< QgsSymbolV2* >( node->data( QgsSymbolV2LegendNode::SymbolV2LegacyRuleKeyRole ).value<void*>() );
1062  if ( symbolKey )
1063  {
1065  if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( node->layerNode()->layer() ) )
1066  {
1067  if ( mLegendFilterHitTest->legendKeyVisible( ruleKey, vl ) )
1068  filtered << node;
1069  }
1070  }
1071  else // unknown node type
1072  filtered << node;
1073  }
1074  }
1075  else
1076  {
1077  return nodes;
1078  }
1079 
1080  return filtered;
1081 }
1082 
1083 
1084 
1086 // Legend nodes routines - start
1087 
1089 {
1090  Q_FOREACH ( const LayerLegendData& data, mLegend )
1091  {
1092  qDeleteAll( data.originalNodes );
1093  delete data.tree;
1094  }
1095  mLegend.clear();
1096 }
1097 
1098 
1100 {
1101  if ( mLegend.contains( nodeLayer ) )
1102  {
1103  qDeleteAll( mLegend[nodeLayer].originalNodes );
1104  delete mLegend[nodeLayer].tree;
1105  mLegend.remove( nodeLayer );
1106  }
1107 }
1108 
1109 
1111 {
1112  if ( !nodeL->layer() )
1113  return;
1114 
1115  QgsMapLayer* ml = nodeL->layer();
1116  QgsMapLayerLegend* layerLegend = ml->legend();
1117  if ( !layerLegend )
1118  return;
1119 
1120  bool hasStyleOverride = mLayerStyleOverrides.contains( ml->id() );
1121  if ( hasStyleOverride )
1123 
1125 
1126  // apply filtering defined in layer node's custom properties (reordering, filtering, custom labels)
1128 
1129  QList<QgsLayerTreeModelLegendNode*> filteredLstNew = filterLegendNodes( lstNew );
1130 
1131  bool isEmbedded = filteredLstNew.count() == 1 && filteredLstNew[0]->isEmbeddedInParent();
1132 
1133  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, lstNew )
1134  {
1135  n->setParent( this );
1136  connect( n, SIGNAL( dataChanged() ), this, SLOT( legendNodeDataChanged() ) );
1137  }
1138 
1140  data.originalNodes = lstNew;
1141  data.activeNodes = filteredLstNew;
1142  data.tree = nullptr;
1143 
1144  // maybe the legend nodes form a tree - try to create a tree structure from the list
1145  if ( testFlag( ShowLegendAsTree ) )
1146  tryBuildLegendTree( data );
1147 
1148  int count = data.tree ? data.tree->children[nullptr].count() : filteredLstNew.count();
1149 
1150  if ( ! isEmbedded ) beginInsertRows( node2index( nodeL ), 0, count - 1 );
1151 
1152  mLegend[nodeL] = data;
1153 
1154  if ( ! isEmbedded ) endInsertRows();
1155 
1156  if ( hasStyleOverride )
1158 
1159  // invalidate map based data even if the data is not map-based to make sure
1160  // the symbol sizes are computed at least once
1162 }
1163 
1164 
1166 {
1167  // first check whether there are any legend nodes that are not top-level
1168  bool hasParentKeys = false;
1169  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1170  {
1172  {
1173  hasParentKeys = true;
1174  break;
1175  }
1176  }
1177  if ( !hasParentKeys )
1178  return; // all legend nodes are top-level => stick with list representation
1179 
1180  // make mapping from rules to nodes and do some sanity checks
1182  rule2node[QString()] = nullptr;
1183  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1184  {
1186  if ( ruleKey.isEmpty() ) // in tree all nodes must have key
1187  return;
1188  if ( rule2node.contains( ruleKey ) ) // and they must be unique
1189  return;
1190  rule2node[ruleKey] = n;
1191  }
1192 
1193  // create the tree structure
1194  data.tree = new LayerLegendTree;
1195  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1196  {
1198  QgsLayerTreeModelLegendNode* parent = rule2node.value( parentRuleKey, nullptr );
1199  data.tree->parents[n] = parent;
1200  data.tree->children[parent] << n;
1201  }
1202 }
1203 
1204 
1206 {
1207  return qobject_cast<QgsLayerTreeModelLegendNode*>( reinterpret_cast<QObject*>( index.internalPointer() ) );
1208 }
1209 
1210 
1212 {
1213  const LayerLegendData& data = mLegend[legendNode->layerNode()];
1214  if ( data.tree )
1215  {
1216  if ( QgsLayerTreeModelLegendNode* parentLegendNode = data.tree->parents[legendNode] )
1217  {
1218  QModelIndex parentIndex = legendNode2index( parentLegendNode );
1219  int row = data.tree->children[parentLegendNode].indexOf( legendNode );
1220  return index( row, 0, parentIndex );
1221  }
1222  else
1223  {
1224  QModelIndex parentIndex = node2index( legendNode->layerNode() );
1225  int row = data.tree->children[nullptr].indexOf( legendNode );
1226  return index( row, 0, parentIndex );
1227  }
1228  }
1229 
1230  QModelIndex parentIndex = node2index( legendNode->layerNode() );
1231  Q_ASSERT( parentIndex.isValid() );
1232  int row = data.activeNodes.indexOf( legendNode );
1233  if ( row < 0 ) // legend node may be filtered (exists within the list of original nodes, but not in active nodes)
1234  return QModelIndex();
1235  return index( row, 0, parentIndex );
1236 }
1237 
1238 
1240 {
1241  const LayerLegendData& data = mLegend[node->layerNode()];
1242  if ( data.tree )
1243  return data.tree->children[node].count();
1244 
1245  return 0; // they are leaves
1246 }
1247 
1248 
1250 {
1251  if ( legendEmbeddedInParent( nL ) )
1252  return 0;
1253 
1254  if ( !mLegend.contains( nL ) )
1255  return 0;
1256 
1257  const LayerLegendData& data = mLegend[nL];
1258  if ( data.tree )
1259  return data.tree->children[nullptr].count();
1260 
1261  return data.activeNodes.count();
1262 }
1263 
1264 
1266 {
1267  Q_ASSERT( mLegend.contains( nL ) );
1268  const LayerLegendData& data = mLegend[nL];
1269  if ( data.tree )
1270  return createIndex( row, column, static_cast<QObject*>( data.tree->children[nullptr].at( row ) ) );
1271 
1272  return createIndex( row, column, static_cast<QObject*>( data.activeNodes.at( row ) ) );
1273 }
1274 
1275 
1277 {
1278  const LayerLegendData& data = mLegend[node->layerNode()];
1279  if ( data.tree )
1280  return createIndex( row, column, static_cast<QObject*>( data.tree->children[node].at( row ) ) );
1281 
1282  return QModelIndex(); // have no children
1283 }
1284 
1285 
1287 {
1288  QgsLayerTreeLayer* layerNode = legendNode->layerNode();
1289  const LayerLegendData& data = mLegend[layerNode];
1290  if ( data.tree )
1291  {
1292  if ( QgsLayerTreeModelLegendNode* parentNode = data.tree->parents[legendNode] )
1293  {
1294  QgsLayerTreeModelLegendNode* grandParentNode = data.tree->parents[parentNode]; // may be null (not a problem)
1295  int row = data.tree->children[grandParentNode].indexOf( parentNode );
1296  return createIndex( row, 0, static_cast<QObject*>( parentNode ) );
1297  }
1298  else
1299  return indexOfParentLayerTreeNode( layerNode );
1300  }
1301 
1302  return indexOfParentLayerTreeNode( layerNode );
1303 }
1304 
1305 
1307 {
1308  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
1309  return QVariant();
1310  return node->data( role );
1311 }
1312 
1313 
1315 {
1316  Qt::ItemFlags f = node->flags();
1317  if ( !testFlag( AllowLegendChangeState ) )
1318  f &= ~Qt::ItemIsUserCheckable;
1319  return f;
1320 }
1321 
1322 
1324 {
1325  const LayerLegendData& data = mLegend[nodeLayer];
1326  return data.activeNodes.count() == 1 && data.activeNodes[0]->isEmbeddedInParent();
1327 }
1328 
1329 
1331 {
1332  return QIcon( qvariant_cast<QPixmap>( mLegend[nodeLayer].activeNodes[0]->data( Qt::DecorationRole ) ) );
1333 }
1334 
1335 
1337 {
1338  return mLegend.value( nodeLayer ).activeNodes;
1339 }
1340 
1342 {
1343  return mLegend.value( nodeLayer ).originalNodes;
1344 }
1345 
1347 {
1349  for ( ; it != mLegend.constEnd(); ++it )
1350  {
1351  QgsLayerTreeLayer* layer = it.key();
1352  if ( layer->layerId() == layerId )
1353  {
1354  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, mLegend.value( layer ).activeNodes )
1355  {
1356  if ( legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() == ruleKey )
1357  {
1358  //found it!
1359  return legendNode;
1360  }
1361  }
1362  }
1363  }
1364 
1365  return nullptr;
1366 }
1367 
1369 {
1372  else
1374 }
1375 
1377 {
1378  QgsDebugCall;
1379 
1380  // we have varying icon sizes, and we want icon to be centered and
1381  // text to be left aligned, so we have to compute the max width of icons
1382  //
1383  // we do that for nodes who share a common parent
1384  //
1385  // we do that here because for symbols with size defined in map units
1386  // the symbol sizes changes depends on the zoom level
1387 
1388  Q_FOREACH ( const LayerLegendData& data, mLegend )
1389  {
1390  QList<QgsSymbolV2LegendNode*> symbolNodes;
1391  QMap<QString, int> widthMax;
1392  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, data.originalNodes )
1393  {
1394  QgsSymbolV2LegendNode* n = dynamic_cast<QgsSymbolV2LegendNode*>( legendNode );
1395  if ( n )
1396  {
1397  const QSize sz( n->minimumIconSize() );
1399  widthMax[parentKey] = qMax( sz.width(), widthMax.contains( parentKey ) ? widthMax[parentKey] : 0 );
1400  n->setIconSize( sz );
1401  symbolNodes.append( n );
1402  }
1403  }
1404  Q_FOREACH ( QgsSymbolV2LegendNode* n, symbolNodes )
1405  {
1407  Q_ASSERT( widthMax[parentKey] > 0 );
1408  const int twiceMarginWidth = 2; // a one pixel margin avoids hugly rendering of icon
1409  n->setIconSize( QSize( widthMax[parentKey] + twiceMarginWidth, n->iconSize().rheight() + twiceMarginWidth ) );
1410  }
1411  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, data.originalNodes )
1412  legendNode->invalidateMapBasedData();
1413  }
1414 
1415 }
1416 
1417 // Legend nodes routines - end
bool restoreOverrideStyle()
Restore the original store after a call to setOverrideStyle()
int legendNodeRowCount(QgsLayerTreeModelLegendNode *node) const
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
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.
QList< QgsLayerTreeModelLegendNode * > originalNodes
Data structure for storage of legend nodes.
QModelIndex legendParent(QgsLayerTreeModelLegendNode *legendNode) const
Base class for all map layer types.
Definition: qgsmaplayer.h:49
void setLayerName(const QString &n)
QModelIndex currentIndex() const
Get index of the item marked as current. Item marked as current is underlined.
QMimeData * mimeData(const QModelIndexList &indexes) const override
QList< QgsLayerTreeModelLegendNode * > layerLegendNodes(QgsLayerTreeLayer *nodeLayer)
Return filtered list of active legend nodes attached to a particular layer node.
QIcon legendIconEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Q_DECL_DEPRECATED bool isIndexSymbologyNode(const QModelIndex &index) const
Return true if index represents a legend node (instead of layer node)
QByteArray data(const QString &mimeType) const
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:99
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.
bool contains(const Key &key) const
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.
QgsLayerTreeGroup * rootGroup() const
Return pointer to the root node of the layer tree. Always a non-null pointer.
QDomNode appendChild(const QDomNode &newChild)
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)
static const QIcon & iconPoint()
Definition: qgsdataitem.cpp:98
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QgsMapLayer * layer() const
Qt::ItemFlags legendNodeFlags(QgsLayerTreeModelLegendNode *node) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual bool setData(const QVariant &value, int role)
Set some data associated with the item.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
virtual bool hasFormat(const QString &mimeType) const
QString toString(int indent) const
QObject * sender() const
QgsMapLayerStyleManager * styleManager() const
Get access to the layer&#39;s style manager.
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
static int _numLayerCount(QgsLayerTreeGroup *group, const QString &layerId)
const T & at(int i) const
const QObjectList & children() const
bool legendEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Structure that stores tree representation of map layer&#39;s legend.
void setUnderline(bool enable)
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
QDomElement nextSiblingElement(const QString &tagName) const
Flags flags() const
Return OR-ed combination of model flags.
QList< QgsLayerTreeModelLegendNode * > filterLegendNodes(const QList< QgsLayerTreeModelLegendNode * > &nodes)
Filter nodes from QgsMapLayerLegend according to the current filtering rules.
QSize minimumIconSize() const
Get the minimum icon size to prevent cropping.
T value() const
QPixmap fromImage(const QImage &image, QFlags< Qt::ImageConversionFlag > flags)
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
void recursivelyEmitDataChanged(const QModelIndex &index=QModelIndex())
emit dataChanged() for layer tree node items
static bool _isChildOfNode(QgsLayerTreeNode *child, QgsLayerTreeNode *node)
virtual Qt::ItemFlags flags() const
Return item flags associated with the item.
QDomElement documentElement() const
static const QIcon & iconPolygon()
QVariant legendNodeData(QgsLayerTreeModelLegendNode *node, int role) const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
Flags mFlags
Set of flags for the model.
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
void tryBuildLegendTree(LayerLegendData &data)
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)
Definition: qgis.h:285
virtual void writeXML(QDomElement &parentElement)=0
Write layer tree to XML.
void nodeAddedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
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)
QPixmap pixmap(const QSize &size, Mode mode, State state) const
void connectToLayers(QgsLayerTreeGroup *parentGroup)
int & rheight()
void reset(T *other)
The QgsMapSettings class contains configuration for rendering of the map.
int indexOf(const T &value, int from) const
void setBold(bool enable)
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Allow renaming of groups and layers.
const char * name() const
QMap< QString, QString > layerStyleOverrides() const
Get map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
rule key of the parent legend node - for legends with tree hierarchy (QString). Added in 2...
bool isValid() const
Qt::CheckState isVisible() const
int count(const T &value) const
void append(const T &value)
QString fromUtf8(const char *str, int size)
void disconnectFromLayer(QgsLayerTreeLayer *nodeLayer)
QMap< QgsLayerTreeModelLegendNode *, QgsLayerTreeModelLegendNode * > parents
Pointer to parent for each active node. Top-level nodes have null parent. Pointers are not owned...
QTimer mDeferLegendInvalidationTimer
int toInt(bool *ok) const
const Key & key() const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
QModelIndex legendNode2index(QgsLayerTreeModelLegendNode *legendNode)
Return index for a given legend node.
static const QIcon & iconRaster()
void disconnectFromLayers(QgsLayerTreeGroup *parentGroup)
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
void setLegendFilterByMap(const QgsMapSettings *settings)
Force only display of legend nodes which are valid for given map settings.
int legendRootRowCount(QgsLayerTreeLayer *nL) const
virtual QVariant data(int role) const override
Return data associated with the item.
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Return legend node for given index.
bool isEmpty() const
Qt::DropActions supportedDropActions() const override
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes. Searches recursively the whole sub-tree.
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
bool isEmpty() const
void beginRemoveRows(const QModelIndex &parent, int first, int last)
int autoCollapseLegendNodes() const
Return at what number of legend nodes the layer node should be collapsed. -1 means no auto-collapse (...
void legendMapViewData(double *mapUnitsPerPixel, int *dpi, double *scale)
Get hints about map view - to be used in legend nodes.
void setName(const QString &n)
Set group&#39;s name.
QgsLayerTreeLayer * layerNode() const
Return pointer to the parent layer node.
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer...
void * internalPointer() const
This class is a base class for nodes in a layer tree.
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
QgsLayerTreeGroup * mRootNode
Pointer to the root node of the layer tree. Not owned by the model.
QString layerId() const
void setVisible(Qt::CheckState visible)
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
QGis::GeometryType geometryType() const
Returns point, line or polygon.
QMap< QgsLayerTreeModelLegendNode *, QList< QgsLayerTreeModelLegendNode * > > children
List of children for each active node. Top-level nodes are under null pointer key. Pointers are not owned.
static QgsLayerTreeNode * readXML(QDomElement &element)
Read layer tree from XML. Returns new instance.
QString name() const
Get group&#39;s name.
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...
Class that runs a hit test with given map settings.
Definition: qgsmaphittest.h:34
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...
Qt::CheckState isVisible() const
Return the check state of the group node.
void setFlag(Flag f, bool on=true)
Enable or disable a model flag.
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.
static void applyLayerNodeProperties(QgsLayerTreeLayer *nodeLayer, QList< QgsLayerTreeModelLegendNode * > &nodes)
update according to layer node&#39;s custom properties (order of items, user labels for items) ...
QModelIndex createIndex(int row, int column, void *ptr) 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.
const T value(const Key &key) const
bool testFlag(Flag f) const
Check whether a flag is enabled.
double mLegendFilterByScale
scale denominator for filtering of legend nodes (<= 0 means no filtering)
void setParent(QObject *parent)
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 setItalic(bool enable)
void beginInsertRows(const QModelIndex &parent, int first, int last)
QgsMapLayerLegend * legend() const
Can be null.
bool isNull() const
static const QIcon & iconTable()
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...
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.
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.
QModelIndex indexOfParentLayerTreeNode(QgsLayerTreeNode *parentNode) const
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
typedef DropActions
bool isNull() const
QDomElement firstChildElement(const QString &tagName) const
virtual bool isScaleOK(double scale) const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QStringList mimeTypes() const override
virtual QVariant data(int role) const =0
Return data associated with the item.
int column() const
static const QIcon & iconLine()
bool toBool() const
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
QgsLayerTreeLayer * findLayer(const QString &layerId) const
Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tr...
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
for QgsSymbolV2LegendNode only - legacy rule key (void ptr, to be cast to QgsSymbolV2 ptr) ...
Allow user to set node visibility with a check box.
void start(int msec)
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
QFont layerTreeNodeFont(int nodeType) const
Get font for a particular type of layer tree node. nodeType should come from QgsLayerTreeNode::NodeTy...
static bool _isChildOfNodes(QgsLayerTreeNode *child, const QList< QgsLayerTreeNode * > &nodes)
bool contains(const Key &key) const
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
QString tagName() const
bool setOverrideStyle(const QString &styleDef)
Temporarily apply a different style to the layer.
void setData(const QString &mimeType, const QByteArray &data)
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...
QDomElement createElement(const QString &tagName)
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Return layer tree node for given index.
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.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString layerName() const
Q_DECL_DEPRECATED QgsLayerTreeLayer * layerNodeForSymbologyNode(const QModelIndex &index) const
Return layer node to which a legend node belongs to.
void setLegendFilter(const QgsMapSettings *settings, bool useExtent=true, const QgsGeometry &polygon=QgsGeometry(), bool useExpressions=true)
Filter display of legend nodes for given map settings.
QObject * parent() const
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.
void setFlags(const QgsLayerTreeModel::Flags &f)
Set OR-ed combination of model flags.
QScopedPointer< QgsMapSettings > mLegendFilterMapSettings
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:34
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
int count(const Key &key) const
void setIconSize(QSize sz)
Set the icon size.
QModelIndex legendRootIndex(int row, int column, QgsLayerTreeLayer *nL) const
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.
QModelIndex legendNodeIndex(int row, int column, QgsLayerTreeModelLegendNode *node) const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Layer tree node points to a map layer.
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
const T value(const Key &key) const
void setSingleShot(bool singleShot)
void nodeVisibilityChanged(QgsLayerTreeNode *node)
Structure that stores all data associated with one map layer.
typedef ItemFlags
QByteArray toUtf8() const