QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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"
20 
21 #include <QMimeData>
22 #include <QTextStream>
23 
24 #include "qgsdataitem.h"
25 #include "qgsmaphittest.h"
26 #include "qgsmaplayerlegend.h"
27 #include "qgspluginlayer.h"
28 #include "qgsrasterlayer.h"
29 #include "qgsrendererv2.h"
30 #include "qgssymbollayerv2utils.h"
31 #include "qgsvectorlayer.h"
32 
33 
35  : QAbstractItemModel( parent )
36  , mRootNode( rootNode )
37  , mFlags( ShowLegend | AllowLegendChangeState )
38  , mAutoCollapseLegendNodesCount( -1 )
39  , mLegendFilterByScale( 0 )
40  , mLegendMapViewMupp( 0 )
41  , mLegendMapViewDpi( 0 )
42  , mLegendMapViewScale( 0 )
43 {
45 
46  mFontLayer.setBold( true );
47 }
48 
50 {
51  foreach ( QList<QgsLayerTreeModelLegendNode*> nodeL, mOriginalLegendNodes )
52  qDeleteAll( nodeL );
53  mOriginalLegendNodes.clear();
54  mLegendNodes.clear(); // does not own the nodes
55 }
56 
58 {
59  if ( !index.isValid() )
60  return mRootNode;
61 
62  QObject* obj = reinterpret_cast<QObject*>( index.internalPointer() );
63  return qobject_cast<QgsLayerTreeNode*>( obj );
64 }
65 
67 {
68  return qobject_cast<QgsLayerTreeModelLegendNode*>( reinterpret_cast<QObject*>( index.internalPointer() ) );
69 }
70 
72 {
73  QModelIndex parentIndex = node2index( legendNode->layerNode() );
74  Q_ASSERT( parentIndex.isValid() );
75  int row = mLegendNodes[legendNode->layerNode()].indexOf( legendNode );
76  if ( row < 0 ) // legend node may be filtered (exists within the list of original nodes, but not in active nodes)
77  return QModelIndex();
78  return index( row, 0, parentIndex );
79 }
80 
81 
82 int QgsLayerTreeModel::rowCount( const QModelIndex &parent ) const
83 {
84  if ( index2legendNode( parent ) )
85  return 0; // they are leaves
86 
87  QgsLayerTreeNode* n = index2node( parent );
88  if ( !n )
89  return 0;
90 
91  if ( QgsLayerTree::isLayer( n ) )
92  {
93  if ( !testFlag( ShowLegend ) )
94  return 0;
95 
97  if ( mLegendNodes[nL].count() == 1 && mLegendNodes[nL][0]->isEmbeddedInParent() )
98  return 0;
99 
100  return mLegendNodes[nL].count();
101  }
102 
103  return n->children().count();
104 }
105 
106 int QgsLayerTreeModel::columnCount( const QModelIndex &parent ) const
107 {
108  Q_UNUSED( parent );
109  return 1;
110 }
111 
112 QModelIndex QgsLayerTreeModel::index( int row, int column, const QModelIndex &parent ) const
113 {
114  if ( column < 0 || column >= columnCount( parent ) ||
115  row < 0 || row >= rowCount( parent ) )
116  return QModelIndex();
117 
118  QgsLayerTreeNode *n = index2node( parent );
119  if ( !n )
120  return QModelIndex(); // have no children
121 
122  if ( testFlag( ShowLegend ) && QgsLayerTree::isLayer( n ) )
123  {
125  Q_ASSERT( mLegendNodes.contains( nL ) );
126  return createIndex( row, column, static_cast<QObject*>( mLegendNodes[nL].at( row ) ) );
127  }
128 
129  return createIndex( row, column, static_cast<QObject*>( n->children().at( row ) ) );
130 }
131 
132 QModelIndex QgsLayerTreeModel::parent( const QModelIndex &child ) const
133 {
134  if ( !child.isValid() )
135  return QModelIndex();
136 
137  QgsLayerTreeNode *parentNode = 0;
138  QgsLayerTreeNode *n = index2node( child );
139  if ( !n )
140  {
142  Q_ASSERT( sym );
143  parentNode = sym->layerNode();
144  }
145  else
146  {
147  parentNode = n->parent(); // must not be null
148  }
149 
150  Q_ASSERT( parentNode );
151 
152  QgsLayerTreeNode* grandParentNode = parentNode->parent();
153  if ( !grandParentNode )
154  return QModelIndex(); // root node -> invalid index
155 
156  int row = grandParentNode->children().indexOf( parentNode );
157  Q_ASSERT( row >= 0 );
158 
159  return createIndex( row, 0, static_cast<QObject*>( parentNode ) );
160 }
161 
162 QVariant QgsLayerTreeModel::data( const QModelIndex &index, int role ) const
163 {
164  if ( !index.isValid() || index.column() > 1 )
165  return QVariant();
166 
167  if ( QgsLayerTreeModelLegendNode* sym = index2legendNode( index ) )
168  {
169  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
170  return QVariant();
171  return sym->data( role );
172  }
173 
174  QgsLayerTreeNode* node = index2node( index );
175  if ( role == Qt::DisplayRole || role == Qt::EditRole )
176  {
177  if ( QgsLayerTree::isGroup( node ) )
178  return QgsLayerTree::toGroup( node )->name();
179 
180  if ( QgsLayerTree::isLayer( node ) )
181  {
182  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
183  QString name = nodeLayer->layerName();
184  if ( nodeLayer->customProperty( "showFeatureCount", 0 ).toInt() && role == Qt::DisplayRole )
185  {
186  QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( nodeLayer->layer() );
187  if ( vlayer && vlayer->pendingFeatureCount() >= 0 )
188  name += QString( " [%1]" ).arg( vlayer->pendingFeatureCount() );
189  }
190  return name;
191  }
192  }
193  else if ( role == Qt::DecorationRole && index.column() == 0 )
194  {
195  if ( QgsLayerTree::isGroup( node ) )
196  return iconGroup();
197 
198  if ( QgsLayerTree::isLayer( node ) )
199  {
200  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
201 
202  QgsMapLayer *layer = nodeLayer->layer();
203  if ( !layer )
204  return QVariant();
205 
206  // icons possibly overriding default icon
207  if ( layer->type() == QgsMapLayer::RasterLayer )
208  {
210  {
211  QgsRasterLayer* rlayer = qobject_cast<QgsRasterLayer *>( layer );
212  return QIcon( rlayer->previewAsPixmap( QSize( 32, 32 ) ) );
213  }
214  }
215 
216  QgsVectorLayer *vlayer = dynamic_cast<QgsVectorLayer*>( layer );
217 
218  if ( layer->type() == QgsMapLayer::RasterLayer )
219  {
220  return QgsLayerItem::iconRaster();
221  }
222 
223  QIcon icon;
224 
225  // if there's just on legend entry that should be embedded in layer - do that!
226  if ( testFlag( ShowLegend ) && mLegendNodes[nodeLayer].count() == 1 && mLegendNodes[nodeLayer][0]->isEmbeddedInParent() )
227  {
228  icon = QIcon( qvariant_cast<QPixmap>( mLegendNodes[nodeLayer][0]->data( Qt::DecorationRole ) ) );
229  }
230  else if ( layer->type() == QgsMapLayer::VectorLayer )
231  {
232  if ( vlayer->geometryType() == QGis::Point )
233  icon = QgsLayerItem::iconPoint();
234  else if ( vlayer->geometryType() == QGis::Line )
235  icon = QgsLayerItem::iconLine();
236  else if ( vlayer->geometryType() == QGis::Polygon )
237  icon = QgsLayerItem::iconPolygon();
238  else if ( vlayer->geometryType() == QGis::NoGeometry )
239  icon = QgsLayerItem::iconTable();
240  else
241  icon = QgsLayerItem::iconDefault();
242  }
243 
244  if ( vlayer && vlayer->isEditable() )
245  {
246  QPixmap pixmap( icon.pixmap( 16, 16 ) );
247 
248  QPainter painter( &pixmap );
249  painter.drawPixmap( 0, 0, 16, 16, QgsApplication::getThemePixmap( vlayer->isModified() ? "/mIconEditableEdits.png" : "/mIconEditable.png" ) );
250  painter.end();
251 
252  icon = QIcon( pixmap );
253  }
254 
255  return icon;
256  }
257  }
258  else if ( role == Qt::CheckStateRole )
259  {
261  return QVariant();
262 
263  if ( QgsLayerTree::isLayer( node ) )
264  {
265  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
266  if ( nodeLayer->layer() && nodeLayer->layer()->type() == QgsMapLayer::VectorLayer )
267  {
268  if ( qobject_cast<QgsVectorLayer*>( nodeLayer->layer() )->geometryType() == QGis::NoGeometry )
269  return QVariant(); // do not show checkbox for non-spatial tables
270  }
271  return nodeLayer->isVisible();
272  }
273  else if ( QgsLayerTree::isGroup( node ) )
274  {
275  QgsLayerTreeGroup* nodeGroup = QgsLayerTree::toGroup( node );
276  return nodeGroup->isVisible();
277  }
278  }
279  else if ( role == Qt::FontRole )
280  {
281  QFont f( QgsLayerTree::isLayer( node ) ? mFontLayer : ( QgsLayerTree::isGroup( node ) ? mFontGroup : QFont() ) );
282  if ( node->customProperty( "embedded" ).toInt() )
283  f.setItalic( true );
284  if ( index == mCurrentIndex )
285  f.setUnderline( true );
286  return f;
287  }
288  else if ( role == Qt::ToolTipRole )
289  {
290  if ( QgsLayerTree::isLayer( node ) )
291  {
292  if ( QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer() )
293  return layer->publicSource();
294  }
295  }
296 
297  return QVariant();
298 }
299 
300 Qt::ItemFlags QgsLayerTreeModel::flags( const QModelIndex& index ) const
301 {
302  if ( !index.isValid() )
303  {
304  Qt::ItemFlags rootFlags = 0;
305  if ( testFlag( AllowNodeReorder ) )
306  rootFlags |= Qt::ItemIsDropEnabled;
307  return rootFlags;
308  }
309 
310  if ( QgsLayerTreeModelLegendNode* symn = index2legendNode( index ) )
311  {
312  Qt::ItemFlags f = symn->flags();
314  f &= ~Qt::ItemIsUserCheckable;
315  return f;
316  }
317 
318  Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
319 
320  if ( testFlag( AllowNodeRename ) )
321  f |= Qt::ItemIsEditable;
322 
323  QgsLayerTreeNode* node = index2node( index );
324  bool isEmbedded = node->customProperty( "embedded" ).toInt();
325 
326  if ( testFlag( AllowNodeReorder ) )
327  {
328  // only root embedded nodes can be reordered
329  if ( !isEmbedded || ( isEmbedded && node->parent() && !node->parent()->customProperty( "embedded" ).toInt() ) )
330  f |= Qt::ItemIsDragEnabled;
331  }
332 
334  f |= Qt::ItemIsUserCheckable;
335 
336  if ( testFlag( AllowNodeReorder ) && QgsLayerTree::isGroup( node ) && !isEmbedded )
337  f |= Qt::ItemIsDropEnabled;
338 
339  return f;
340 }
341 
342 bool QgsLayerTreeModel::setData( const QModelIndex& index, const QVariant& value, int role )
343 {
345  if ( sym )
346  {
347  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
348  return false;
349  bool res = sym->setData( value, role );
350  if ( res )
351  emit dataChanged( index, index );
352  return res;
353  }
354 
355  QgsLayerTreeNode* node = index2node( index );
356  if ( !node )
357  return QgsLayerTreeModel::setData( index, value, role );
358 
359  if ( role == Qt::CheckStateRole )
360  {
362  return false;
363 
364  if ( QgsLayerTree::isLayer( node ) )
365  {
366  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
367  layer->setVisible(( Qt::CheckState )value.toInt() );
368  return true;
369  }
370 
371  if ( QgsLayerTree::isGroup( node ) )
372  {
373  QgsLayerTreeGroup* group = QgsLayerTree::toGroup( node );
374  group->setVisible(( Qt::CheckState )value.toInt() );
375  return true;
376  }
377 
378  return true;
379  }
380  else if ( role == Qt::EditRole )
381  {
382  if ( !testFlag( AllowNodeRename ) )
383  return false;
384 
385  if ( QgsLayerTree::isLayer( node ) )
386  {
387  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
388  layer->setLayerName( value.toString() );
389  emit dataChanged( index, index );
390  }
391  else if ( QgsLayerTree::isGroup( node ) )
392  {
393  QgsLayerTree::toGroup( node )->setName( value.toString() );
394  emit dataChanged( index, index );
395  }
396  }
397 
398  return QAbstractItemModel::setData( index, value, role );
399 }
400 
402 {
403  if ( !node->parent() )
404  return QModelIndex(); // this is the only root item -> invalid index
405 
406  QModelIndex parentIndex = node2index( node->parent() );
407 
408  int row = node->parent()->children().indexOf( node );
409  Q_ASSERT( row >= 0 );
410  return index( row, 0, parentIndex );
411 }
412 
413 
415 {
416  if ( !child->parent() )
417  return false;
418 
419  if ( child->parent() == node )
420  return true;
421 
422  return _isChildOfNode( child->parent(), node );
423 }
424 
425 static bool _isChildOfNodes( QgsLayerTreeNode* child, QList<QgsLayerTreeNode*> nodes )
426 {
427  foreach ( QgsLayerTreeNode* n, nodes )
428  {
429  if ( _isChildOfNode( child, n ) )
430  return true;
431  }
432 
433  return false;
434 }
435 
436 
437 QList<QgsLayerTreeNode*> QgsLayerTreeModel::indexes2nodes( const QModelIndexList& list, bool skipInternal ) const
438 {
439  QList<QgsLayerTreeNode*> nodes;
440  foreach ( QModelIndex index, list )
441  {
442  QgsLayerTreeNode* node = index2node( index );
443  if ( !node )
444  continue;
445 
446  nodes << node;
447  }
448 
449  if ( !skipInternal )
450  return nodes;
451 
452  // remove any children of nodes if both parent node and children are selected
453  QList<QgsLayerTreeNode*> nodesFinal;
454  foreach ( QgsLayerTreeNode* node, nodes )
455  {
456  if ( !_isChildOfNodes( node, nodes ) )
457  nodesFinal << node;
458  }
459 
460  return nodesFinal;
461 }
462 
463 bool QgsLayerTreeModel::isIndexSymbologyNode( const QModelIndex& index ) const
464 {
465  return index2legendNode( index ) != 0;
466 }
467 
469 {
470  QgsLayerTreeModelLegendNode* symNode = index2legendNode( index );
471  return symNode ? symNode->layerNode() : 0;
472 }
473 
474 QList<QgsLayerTreeModelLegendNode*> QgsLayerTreeModel::layerLegendNodes( QgsLayerTreeLayer* nodeLayer )
475 {
476  return mLegendNodes.value( nodeLayer );
477 }
478 
480 {
481  return mRootNode;
482 }
483 
485 {
486  beginResetModel();
487 
489 
490  Q_ASSERT( mLegendNodes.isEmpty() );
491  Q_ASSERT( mOriginalLegendNodes.isEmpty() );
492 
493  mRootNode = newRootGroup;
494 
495  endResetModel();
496 
498 }
499 
501 {
502  // update title
503  QModelIndex idx = node2index( nodeLayer );
504  emit dataChanged( idx, idx );
505 
506  // update children
507  int oldNodeCount = rowCount( idx );
508  beginRemoveRows( idx, 0, oldNodeCount - 1 );
509  removeLegendFromLayer( nodeLayer );
510  endRemoveRows();
511 
512  addLegendToLayer( nodeLayer );
513  int newNodeCount = rowCount( idx );
514 
515  // automatic collapse of legend nodes - useful if a layer has many legend nodes
516  if ( mAutoCollapseLegendNodesCount != -1 && oldNodeCount != newNodeCount && newNodeCount >= mAutoCollapseLegendNodesCount )
517  nodeLayer->setExpanded( false );
518 }
519 
521 {
522  return mCurrentIndex;
523 }
524 
525 void QgsLayerTreeModel::setCurrentIndex( const QModelIndex& currentIndex )
526 {
527  QModelIndex oldIndex = mCurrentIndex;
529 
530  if ( oldIndex.isValid() )
531  emit dataChanged( oldIndex, oldIndex );
532  if ( currentIndex.isValid() )
533  emit dataChanged( currentIndex, currentIndex );
534 }
535 
536 
537 void QgsLayerTreeModel::setLayerTreeNodeFont( int nodeType, const QFont& font )
538 {
539  if ( nodeType == QgsLayerTreeNode::NodeGroup )
540  {
541  if ( mFontGroup != font )
542  {
543  mFontGroup = font;
545  }
546  }
547  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
548  {
549  if ( mFontLayer != font )
550  {
551  mFontLayer = font;
553  }
554  }
555  else
556  {
557  QgsDebugMsg( "invalid node type" );
558  }
559 }
560 
561 
562 QFont QgsLayerTreeModel::layerTreeNodeFont( int nodeType ) const
563 {
564  if ( nodeType == QgsLayerTreeNode::NodeGroup )
565  return mFontGroup;
566  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
567  return mFontLayer;
568  else
569  {
570  QgsDebugMsg( "invalid node type" );
571  return QFont();
572  }
573 }
574 
575 void QgsLayerTreeModel::setLegendFilterByScale( double scaleDenominator )
576 {
577  mLegendFilterByScale = scaleDenominator;
578 
579  // this could be later done in more efficient way
580  // by just updating active legend nodes, without refreshing original legend nodes
581  foreach ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
582  refreshLayerLegend( nodeLayer );
583 }
584 
586 {
587  if ( settings && settings->hasValidSettings() )
588  {
589  mLegendFilterByMapSettings.reset( new QgsMapSettings( *settings ) );
592  }
593  else
594  {
596  return; // no change
597 
600  }
601 
602  // temporarily disable autocollapse so that legend nodes stay visible
603  int bkAutoCollapse = autoCollapseLegendNodes();
605 
606  // this could be later done in more efficient way
607  // by just updating active legend nodes, without refreshing original legend nodes
608  foreach ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
609  refreshLayerLegend( nodeLayer );
610 
611  setAutoCollapseLegendNodes( bkAutoCollapse );
612 }
613 
614 void QgsLayerTreeModel::setLegendMapViewData( double mapUnitsPerPixel, int dpi, double scale )
615 {
616  if ( mLegendMapViewDpi == dpi && mLegendMapViewMupp == mapUnitsPerPixel && mLegendMapViewScale == scale )
617  return;
618 
619  mLegendMapViewMupp = mapUnitsPerPixel;
620  mLegendMapViewDpi = dpi;
621  mLegendMapViewScale = scale;
622 
623  // now invalidate legend nodes!
624  QMap<QgsLayerTreeLayer*, QList<QgsLayerTreeModelLegendNode*> > x;
625  foreach ( const QList<QgsLayerTreeModelLegendNode*>& lst, mOriginalLegendNodes )
626  {
627  foreach ( QgsLayerTreeModelLegendNode* legendNode, lst )
628  legendNode->invalidateMapBasedData();
629  }
630 }
631 
632 void QgsLayerTreeModel::legendMapViewData( double* mapUnitsPerPixel, int* dpi, double* scale )
633 {
634  if ( mapUnitsPerPixel ) *mapUnitsPerPixel = mLegendMapViewMupp;
635  if ( dpi ) *dpi = mLegendMapViewDpi;
636  if ( scale ) *scale = mLegendMapViewScale;
637 }
638 
639 void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
640 {
641  Q_ASSERT( node );
642  beginInsertRows( node2index( node ), indexFrom, indexTo );
643 }
644 
645 static QList<QgsLayerTreeLayer*> _layerNodesInSubtree( QgsLayerTreeNode* node, int indexFrom, int indexTo )
646 {
647  QList<QgsLayerTreeNode*> children = node->children();
648  QList<QgsLayerTreeLayer*> newLayerNodes;
649  for ( int i = indexFrom; i <= indexTo; ++i )
650  {
651  QgsLayerTreeNode* child = children.at( i );
652  if ( QgsLayerTree::isLayer( child ) )
653  newLayerNodes << QgsLayerTree::toLayer( child );
654  else if ( QgsLayerTree::isGroup( child ) )
655  newLayerNodes << QgsLayerTree::toGroup( child )->findLayers();
656  }
657  return newLayerNodes;
658 }
659 
660 void QgsLayerTreeModel::nodeAddedChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
661 {
662  Q_ASSERT( node );
663 
664  endInsertRows();
665 
666  foreach ( QgsLayerTreeLayer* newLayerNode, _layerNodesInSubtree( node, indexFrom, indexTo ) )
667  connectToLayer( newLayerNode );
668 }
669 
670 void QgsLayerTreeModel::nodeWillRemoveChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
671 {
672  Q_ASSERT( node );
673 
674  beginRemoveRows( node2index( node ), indexFrom, indexTo );
675 
676  // disconnect from layers and remove their legend
677  foreach ( QgsLayerTreeLayer* nodeLayer, _layerNodesInSubtree( node, indexFrom, indexTo ) )
678  disconnectFromLayer( nodeLayer );
679 }
680 
682 {
683  endRemoveRows();
684 }
685 
687 {
688  Q_ASSERT( node );
689 
690  QModelIndex index = node2index( node );
691  emit dataChanged( index, index );
692 }
693 
694 
696 {
697  if ( QgsLayerTree::isLayer( node ) && key == "showFeatureCount" )
699 }
700 
701 
703 {
704  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
705  if ( !nodeLayer )
706  return;
707 
708  // deffered connection to the layer
709  connectToLayer( nodeLayer );
710 }
711 
713 {
714  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
715  if ( !nodeLayer )
716  return;
717 
718  disconnectFromLayer( nodeLayer );
719 
720  // wait for the layer to appear again
721  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
722 }
723 
725 {
726  if ( !testFlag( ShowLegend ) )
727  return;
728 
729  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
730  if ( !layer )
731  return;
732 
733  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
734  if ( !nodeLayer )
735  return;
736 
737  refreshLayerLegend( nodeLayer );
738 }
739 
741 {
742  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
743  if ( !layer )
744  return;
745 
746  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
747  if ( !nodeLayer )
748  return;
749 
750  QModelIndex index = node2index( nodeLayer );
751  emit dataChanged( index, index );
752 
753  if ( nodeLayer->customProperty( "showFeatureCount" ).toInt() )
754  refreshLayerLegend( nodeLayer );
755 }
756 
757 
759 {
760  QgsLayerTreeModelLegendNode* legendNode = qobject_cast<QgsLayerTreeModelLegendNode*>( sender() );
761  if ( !legendNode )
762  return;
763 
764  QModelIndex index = legendNode2index( legendNode );
765  if ( index.isValid() )
766  emit dataChanged( index, index );
767 }
768 
769 
771 {
772  if ( mLegendNodes.contains( nodeLayer ) )
773  {
774  qDeleteAll( mOriginalLegendNodes[nodeLayer] );
775  mOriginalLegendNodes.remove( nodeLayer );
776  mLegendNodes.remove( nodeLayer );
777  }
778 }
779 
780 
782 {
783  if ( !nodeL->layer() )
784  return;
785 
786  QgsMapLayerLegend* layerLegend = nodeL->layer()->legend();
787  if ( !layerLegend )
788  return;
789 
790  QList<QgsLayerTreeModelLegendNode*> lstNew = layerLegend->createLayerTreeModelLegendNodes( nodeL );
791 
792  // apply filtering defined in layer node's custom properties (reordering, filtering, custom labels)
794 
795  QList<QgsLayerTreeModelLegendNode*> filteredLstNew = filterLegendNodes( lstNew );
796 
797  beginInsertRows( node2index( nodeL ), 0, filteredLstNew.count() - 1 );
798 
799  foreach ( QgsLayerTreeModelLegendNode* n, lstNew )
800  {
801  n->setParent( this );
802  connect( n, SIGNAL( dataChanged() ), this, SLOT( legendNodeDataChanged() ) );
803  }
804 
805  mOriginalLegendNodes[nodeL] = lstNew;
806  mLegendNodes[nodeL] = filteredLstNew;
807 
808  endInsertRows();
809 }
810 
811 
813 {
814  if ( !nodeLayer->layer() )
815  {
816  // in order to connect to layer, we need to have it loaded.
817  // keep an eye on the layer ID: once loaded, we will use it
818  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
819  return;
820  }
821 
822  // watch if the layer is getting removed
823  connect( nodeLayer, SIGNAL( layerWillBeUnloaded() ), this, SLOT( nodeLayerWillBeUnloaded() ) );
824 
825  if ( testFlag( ShowLegend ) )
826  {
827  addLegendToLayer( nodeLayer );
828 
829  // automatic collapse of legend nodes - useful if a layer has many legend nodes
830  if ( !mRootNode->customProperty( "loading" ).toBool() )
831  {
833  nodeLayer->setExpanded( false );
834  }
835  }
836 
837  QgsMapLayer* layer = nodeLayer->layer();
838  connect( layer, SIGNAL( legendChanged() ), this, SLOT( layerLegendChanged() ), Qt::UniqueConnection );
839 
840  if ( layer->type() == QgsMapLayer::VectorLayer )
841  {
842  // using unique connection because there may be temporarily more nodes for a layer than just one
843  // which would create multiple connections, however disconnect() would disconnect all multiple connections
844  // even if we wanted to disconnect just one connection in each call.
845  connect( layer, SIGNAL( editingStarted() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
846  connect( layer, SIGNAL( editingStopped() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
847  connect( layer, SIGNAL( layerModified() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
848  connect( layer, SIGNAL( layerNameChanged() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
849  }
850 }
851 
852 // try to find out if the layer ID is present in the tree multiple times
853 static int _numLayerCount( QgsLayerTreeGroup* group, const QString& layerId )
854 {
855  int count = 0;
856  foreach ( QgsLayerTreeNode* child, group->children() )
857  {
858  if ( QgsLayerTree::isLayer( child ) )
859  {
860  if ( QgsLayerTree::toLayer( child )->layerId() == layerId )
861  count++;
862  }
863  else if ( QgsLayerTree::isGroup( child ) )
864  {
865  count += _numLayerCount( QgsLayerTree::toGroup( child ), layerId );
866  }
867  }
868  return count;
869 }
870 
872 {
873  disconnect( nodeLayer, 0, this, 0 ); // disconnect from delayed load of layer
874 
875  if ( !nodeLayer->layer() )
876  return; // we were never connected
877 
878  if ( testFlag( ShowLegend ) )
879  {
880  removeLegendFromLayer( nodeLayer );
881  }
882 
883  if ( _numLayerCount( mRootNode, nodeLayer->layerId() ) == 1 )
884  {
885  // last instance of the layer in the tree: disconnect from all signals from layer!
886  disconnect( nodeLayer->layer(), 0, this, 0 );
887  }
888 }
889 
891 {
892  foreach ( QgsLayerTreeNode* node, parentGroup->children() )
893  {
894  if ( QgsLayerTree::isGroup( node ) )
896  else if ( QgsLayerTree::isLayer( node ) )
898  }
899 }
900 
902 {
903  foreach ( QgsLayerTreeNode* node, parentGroup->children() )
904  {
905  if ( QgsLayerTree::isGroup( node ) )
907  else if ( QgsLayerTree::isLayer( node ) )
909  }
910 }
911 
913 {
914  Q_ASSERT( mRootNode );
915 
916  connect( mRootNode, SIGNAL( willAddChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillAddChildren( QgsLayerTreeNode*, int, int ) ) );
917  connect( mRootNode, SIGNAL( addedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeAddedChildren( QgsLayerTreeNode*, int, int ) ) );
918  connect( mRootNode, SIGNAL( willRemoveChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillRemoveChildren( QgsLayerTreeNode*, int, int ) ) );
919  connect( mRootNode, SIGNAL( removedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeRemovedChildren() ) );
920  connect( mRootNode, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
921 
922  connect( mRootNode, SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ), this, SLOT( nodeCustomPropertyChanged( QgsLayerTreeNode*, QString ) ) );
923 
925 }
926 
928 {
929  disconnect( mRootNode, 0, this, 0 );
930 
932 }
933 
934 void QgsLayerTreeModel::recursivelyEmitDataChanged( const QModelIndex& idx )
935 {
936  QgsLayerTreeNode* node = index2node( idx );
937  if ( !node )
938  return;
939 
940  int count = node->children().count();
941  if ( count == 0 )
942  return;
943  emit dataChanged( index( 0, 0, idx ), index( count - 1, 0, idx ) );
944  for ( int i = 0; i < count; ++i )
945  recursivelyEmitDataChanged( index( i, 0, idx ) );
946 }
947 
948 
950 {
951  return Qt::MoveAction;
952 }
953 
954 QStringList QgsLayerTreeModel::mimeTypes() const
955 {
956  QStringList types;
957  types << "application/qgis.layertreemodeldata";
958  return types;
959 }
960 
961 
962 QMimeData* QgsLayerTreeModel::mimeData( const QModelIndexList& indexes ) const
963 {
964  QList<QgsLayerTreeNode*> nodesFinal = indexes2nodes( indexes, true );
965 
966  if ( nodesFinal.count() == 0 )
967  return 0;
968 
969  QMimeData *mimeData = new QMimeData();
970 
971  QDomDocument doc;
972  QDomElement rootElem = doc.createElement( "layer_tree_model_data" );
973  foreach ( QgsLayerTreeNode* node, nodesFinal )
974  node->writeXML( rootElem );
975  doc.appendChild( rootElem );
976  QString txt = doc.toString();
977 
978  mimeData->setData( "application/qgis.layertreemodeldata", txt.toUtf8() );
979  return mimeData;
980 }
981 
982 bool QgsLayerTreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
983 {
984  if ( action == Qt::IgnoreAction )
985  return true;
986 
987  if ( !data->hasFormat( "application/qgis.layertreemodeldata" ) )
988  return false;
989 
990  if ( column >= columnCount( parent ) )
991  return false;
992 
993  QgsLayerTreeNode* nodeParent = index2node( parent );
994  if ( !QgsLayerTree::isGroup( nodeParent ) )
995  return false;
996 
997  QByteArray encodedData = data->data( "application/qgis.layertreemodeldata" );
998 
999  QDomDocument doc;
1000  if ( !doc.setContent( QString::fromUtf8( encodedData ) ) )
1001  return false;
1002 
1003  QDomElement rootElem = doc.documentElement();
1004  if ( rootElem.tagName() != "layer_tree_model_data" )
1005  return false;
1006 
1007  QList<QgsLayerTreeNode*> nodes;
1008 
1009  QDomElement elem = rootElem.firstChildElement();
1010  while ( !elem.isNull() )
1011  {
1013  if ( node )
1014  nodes << node;
1015 
1016  elem = elem.nextSiblingElement();
1017  }
1018 
1019  if ( nodes.count() == 0 )
1020  return false;
1021 
1022  if ( parent.isValid() && row == -1 )
1023  row = 0; // if dropped directly onto group item, insert at first position
1024 
1025  QgsLayerTree::toGroup( nodeParent )->insertChildNodes( row, nodes );
1026 
1027  return true;
1028 }
1029 
1030 bool QgsLayerTreeModel::removeRows( int row, int count, const QModelIndex& parent )
1031 {
1032  QgsLayerTreeNode* parentNode = index2node( parent );
1033  if ( QgsLayerTree::isGroup( parentNode ) )
1034  {
1035  QgsLayerTree::toGroup( parentNode )->removeChildren( row, count );
1036  return true;
1037  }
1038  return false;
1039 }
1040 
1041 void QgsLayerTreeModel::setFlags( QgsLayerTreeModel::Flags f )
1042 {
1043  mFlags = f;
1044 }
1045 
1047 {
1048  if ( on )
1049  mFlags |= f;
1050  else
1051  mFlags &= ~f;
1052 }
1053 
1054 QgsLayerTreeModel::Flags QgsLayerTreeModel::flags() const
1055 {
1056  return mFlags;
1057 }
1058 
1060 {
1061  return mFlags.testFlag( f );
1062 }
1063 
1065 {
1066  static QIcon icon;
1067 
1068  if ( icon.isNull() )
1069  icon = QgsApplication::getThemeIcon( "/mActionFolder.png" );
1070 
1071  return icon;
1072 }
1073 
1074 QList<QgsLayerTreeModelLegendNode*> QgsLayerTreeModel::filterLegendNodes( const QList<QgsLayerTreeModelLegendNode*>& nodes )
1075 {
1076  QList<QgsLayerTreeModelLegendNode*> filtered;
1077 
1078  if ( mLegendFilterByScale > 0 )
1079  {
1080  foreach ( QgsLayerTreeModelLegendNode* node, nodes )
1081  {
1082  if ( node->isScaleOK( mLegendFilterByScale ) )
1083  filtered << node;
1084  }
1085  }
1086  else if ( mLegendFilterByMapSettings )
1087  {
1088  foreach ( QgsLayerTreeModelLegendNode* node, nodes )
1089  {
1090  QgsSymbolV2* ruleKey = ( QgsSymbolV2* ) node->data( QgsSymbolV2LegendNode::SymbolV2LegacyRuleKeyRole ).value<void*>();
1091  if ( ruleKey )
1092  {
1093  if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( node->layerNode()->layer() ) )
1094  {
1095  if ( mLegendFilterByMapHitTest->symbolsForLayer( vl ).contains( ruleKey ) )
1096  filtered << node;
1097  }
1098  }
1099  else // unknown node type
1100  filtered << node;
1101  }
1102  }
1103  else
1104  {
1105  return nodes;
1106  }
1107 
1108  return filtered;
1109 }
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.
int columnCount(const QModelIndex &parent=QModelIndex()) const
static unsigned index
Base class for all map layer types.
Definition: qgsmaplayer.h:48
void setLayerName(const QString &n)
QModelIndex currentIndex() const
Get index of the item marked as current. Item marked as current is underlined.
QList< QgsLayerTreeModelLegendNode * > layerLegendNodes(QgsLayerTreeLayer *nodeLayer)
Return list of legend nodes attached to a particular layer node.
Q_DECL_DEPRECATED bool isIndexSymbologyNode(const QModelIndex &index) const
Return true if index represents a legend node (instead of layer node)
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:89
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.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
QgsLayerTreeGroup * rootGroup() const
Return pointer to the root node of the layer tree. Always a non-null pointer.
static const QIcon & iconDefault()
Definition: qgsdataitem.cpp:95
void nodeCustomPropertyChanged(QgsLayerTreeNode *node, const QString &key)
void addLegendToLayer(QgsLayerTreeLayer *nodeL)
static const QIcon & iconPoint()
Definition: qgsdataitem.cpp:45
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QgsMapLayer * layer() 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.
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
static int _numLayerCount(QgsLayerTreeGroup *group, const QString &layerId)
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.
void recursivelyEmitDataChanged(const QModelIndex &index=QModelIndex())
emit dataChanged() for layer tree node items
static bool _isChildOfNode(QgsLayerTreeNode *child, QgsLayerTreeNode *node)
static const QIcon & iconPolygon()
Definition: qgsdataitem.cpp:65
QScopedPointer< QgsMapSettings > mLegendFilterByMapSettings
void insertChildNodes(int index, 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.
QScopedPointer< QgsMapHitTest > mLegendFilterByMapHitTest
static QIcon icon(QString icon)
int rowCount(const QModelIndex &parent=QModelIndex()) const
Flags mFlags
Set of flags for the model.
static QPixmap getThemePixmap(const QString &theName)
Helper to get a theme icon as a pixmap.
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's legend)
void connectToLayers(QgsLayerTreeGroup *parentGroup)
The QgsMapSettings class contains configuration for rendering of the map.
Allow renaming of groups and layers.
Qt::CheckState isVisible() const
void disconnectFromLayer(QgsLayerTreeLayer *nodeLayer)
QModelIndex parent(const QModelIndex &child) const
QModelIndex legendNode2index(QgsLayerTreeModelLegendNode *legendNode)
Return index for a given legend node.
static const QIcon & iconRaster()
Definition: qgsdataitem.cpp:85
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.
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Return legend node for given index.
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.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
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's name.
void setFlags(Flags f)
Set OR-ed combination of model flags.
QgsLayerTreeLayer * layerNode() const
Return pointer to the parent layer node.
QStringList mimeTypes() const
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer...
int pendingFeatureCount()
returns feature count after commit
This class is a base class for nodes in a layer tree.
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:95
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.
static QgsLayerTreeNode * readXML(QDomElement &element)
Read layer tree from XML. Returns new instance.
QString name() const
Get group's name.
Class that runs a hit test with given map settings.
Definition: qgsmaphittest.h:18
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::DropActions supportedDropActions() const
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.
static void applyLayerNodeProperties(QgsLayerTreeLayer *nodeLayer, QList< QgsLayerTreeModelLegendNode * > &nodes)
update according to layer node's custom properties (order of items, user labels for items) ...
QPersistentModelIndex mCurrentIndex
Current index - will be underlined.
Q_DECL_DEPRECATED QPixmap previewAsPixmap(QSize size, QColor bgColor=Qt::white)
Draws a preview of the rasterlayer into a pixmap.
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
void setRootGroup(QgsLayerTreeGroup *newRootGroup)
Reset the model and use a new root group node.
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 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...
QgsMapLayerLegend * legend() const
Can be null.
static const QIcon & iconTable()
Definition: qgsdataitem.cpp:75
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
static bool _isChildOfNodes(QgsLayerTreeNode *child, QList< QgsLayerTreeNode * > nodes)
int mAutoCollapseLegendNodesCount
Minimal number of nodes when legend should be automatically collapsed. -1 = disabled.
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
virtual bool isScaleOK(double scale) const
virtual QVariant data(int role) const =0
Return data associated with the item.
static const QIcon & iconLine()
Definition: qgsdataitem.cpp:55
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
QgsLayerTreeModel(QgsLayerTreeGroup *rootNode, QObject *parent=0)
Construct a new tree model with given layer tree (root node must not be null pointer).
QgsLayerTreeLayer * findLayer(const QString &layerId) const
Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tr...
for QgsSymbolV2LegendNode only - legacy rule key (void ptr, to be cast to QgsSymbolV2 ptr) ...
Allow user to set node visibility with a check box.
QFont layerTreeNodeFont(int nodeType) const
Get font for a particular type of layer tree node. nodeType should come from QgsLayerTreeNode::NodeTy...
QMap< QgsLayerTreeLayer *, QList< QgsLayerTreeModelLegendNode * > > mLegendNodes
Active legend nodes for each layer node.
QMimeData * mimeData(const QModelIndexList &indexes) const
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Return layer tree node for given index.
container of other groups and layers
QString layerName() const
virtual bool isEditable() const
Returns true if the provider is in editing mode.
Q_DECL_DEPRECATED QgsLayerTreeLayer * layerNodeForSymbologyNode(const QModelIndex &index) const
Return layer node to which a legend node belongs to.
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.
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)
Allow reordering with drag'n'drop.
Add legend nodes for layer nodes.
virtual void invalidateMapBasedData()
Notification from model that information from associated map view has changed.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
void nodeWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
QMap< QgsLayerTreeLayer *, QList< QgsLayerTreeModelLegendNode * > > mOriginalLegendNodes
Data structure for storage of legend nodes for each layer.
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer)=0
Return list of legend nodes to be used for a particular layer tree layer node.
Layer tree node points to a map layer.
void nodeVisibilityChanged(QgsLayerTreeNode *node)
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)