QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 "qgsmaplayerlegend.h"
26 #include "qgspluginlayer.h"
27 #include "qgsrasterlayer.h"
28 #include "qgsrendererv2.h"
29 #include "qgssymbollayerv2utils.h"
30 #include "qgsvectorlayer.h"
31 
32 
34  : QAbstractItemModel( parent )
35  , mRootNode( rootNode )
36  , mFlags( ShowLegend | AllowLegendChangeState )
37  , mAutoCollapseLegendNodesCount( -1 )
38 {
40 
41  mFontLayer.setBold( true );
42 }
43 
45 {
46  foreach ( QList<QgsLayerTreeModelLegendNode*> nodeL, mOriginalLegendNodes )
47  qDeleteAll( nodeL );
48  mOriginalLegendNodes.clear();
49  mLegendNodes.clear(); // does not own the nodes
50 }
51 
53 {
54  if ( !index.isValid() )
55  return mRootNode;
56 
57  QObject* obj = reinterpret_cast<QObject*>( index.internalPointer() );
58  return qobject_cast<QgsLayerTreeNode*>( obj );
59 }
60 
62 {
63  return qobject_cast<QgsLayerTreeModelLegendNode*>( reinterpret_cast<QObject*>( index.internalPointer() ) );
64 }
65 
67 {
68  QModelIndex parentIndex = node2index( legendNode->parent() );
69  Q_ASSERT( parentIndex.isValid() );
70  int row = mLegendNodes[legendNode->parent()].indexOf( legendNode );
71  Q_ASSERT( row >= 0 );
72  return index( row, 0, parentIndex );
73 }
74 
75 
76 int QgsLayerTreeModel::rowCount( const QModelIndex &parent ) const
77 {
78  if ( index2legendNode( parent ) )
79  {
80  return 0; // they are leaves
81  }
82 
83  QgsLayerTreeNode* n = index2node( parent );
84 
85  if ( parent.isValid() && parent.column() != 0 )
86  return 0;
87 
88  if ( QgsLayerTree::isLayer( n ) )
89  {
91 
92  if ( mLegendNodes[nL].count() == 1 && mLegendNodes[nL][0]->isEmbeddedInParent() )
93  return 0;
94 
95  return mLegendNodes[nL].count();
96  }
97 
98  return n->children().count();
99 }
100 
101 int QgsLayerTreeModel::columnCount( const QModelIndex &parent ) const
102 {
103  Q_UNUSED( parent );
104  return 1;
105 }
106 
107 QModelIndex QgsLayerTreeModel::index( int row, int column, const QModelIndex &parent ) const
108 {
109  if ( column != 0 || row < 0 || row >= rowCount( parent ) )
110  return QModelIndex();
111 
112  QgsLayerTreeNode* n = index2node( parent );
113 
114  if ( !n )
115  {
117  Q_ASSERT( sym );
118  return QModelIndex(); // have no children
119  }
120 
121  if ( !n || column != 0 || row >= rowCount( parent ) )
122  return QModelIndex();
123 
124  if ( testFlag( ShowLegend ) && QgsLayerTree::isLayer( n ) )
125  {
127  Q_ASSERT( mLegendNodes.contains( nL ) );
128  return createIndex( row, column, static_cast<QObject*>( mLegendNodes[nL].at( row ) ) );
129  }
130 
131  return createIndex( row, column, static_cast<QObject*>( n->children().at( row ) ) );
132 }
133 
134 QModelIndex QgsLayerTreeModel::parent( const QModelIndex &child ) const
135 {
136  if ( !child.isValid() )
137  return QModelIndex();
138 
139  QgsLayerTreeNode* n = index2node( child );
140 
141  QgsLayerTreeNode* parentNode = 0;
142 
143  if ( !n )
144  {
146  Q_ASSERT( sym );
147  parentNode = sym->parent();
148  }
149  else
150  parentNode = n->parent(); // must not be null
151  Q_ASSERT( parentNode );
152 
153  QgsLayerTreeNode* grandParentNode = parentNode->parent();
154  if ( !grandParentNode )
155  return QModelIndex(); // root node -> invalid index
156 
157  int row = grandParentNode->children().indexOf( parentNode );
158  Q_ASSERT( row >= 0 );
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() )
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  else if ( QgsLayerTree::isLayer( node ) )
180  {
181  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
182  QString name = nodeLayer->layerName();
183  if ( nodeLayer->customProperty( "showFeatureCount", 0 ).toInt() && role == Qt::DisplayRole )
184  {
185  QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( nodeLayer->layer() );
186  if ( vlayer && vlayer->pendingFeatureCount() >= 0 )
187  name += QString( " [%1]" ).arg( vlayer->pendingFeatureCount() );
188  }
189  return name;
190  }
191  }
192  else if ( role == Qt::DecorationRole && index.column() == 0 )
193  {
194  if ( QgsLayerTree::isGroup( node ) )
195  return iconGroup();
196  else if ( QgsLayerTree::isLayer( node ) )
197  {
198  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
199 
200  QgsMapLayer* layer = nodeLayer->layer();
201  if ( !layer )
202  return QVariant();
203 
204  // icons possibly overriding default icon
205  if ( layer->type() == QgsMapLayer::RasterLayer )
206  {
208  {
209  QgsRasterLayer* rlayer = qobject_cast<QgsRasterLayer *>( layer );
210  return QIcon( rlayer->previewAsPixmap( QSize( 32, 32 ) ) );
211  }
212  }
213  else if ( layer->type() == QgsMapLayer::VectorLayer )
214  {
215  QgsVectorLayer* vlayer = static_cast<QgsVectorLayer*>( layer );
216  if ( vlayer->isEditable() )
217  {
218  if ( vlayer->isModified() )
219  return QIcon( QgsApplication::getThemePixmap( "/mIconEditableEdits.png" ) );
220  else
221  return QIcon( QgsApplication::getThemePixmap( "/mIconEditable.png" ) );
222  }
223  }
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  return mLegendNodes[nodeLayer][0]->data( Qt::DecorationRole );
228 
229  if ( layer->type() == QgsMapLayer::RasterLayer )
230  {
231  return QgsLayerItem::iconRaster();
232  }
233  else if ( layer->type() == QgsMapLayer::VectorLayer )
234  {
235  QgsVectorLayer* vlayer = static_cast<QgsVectorLayer*>( layer );
236  if ( vlayer->geometryType() == QGis::Point )
237  return QgsLayerItem::iconPoint();
238  else if ( vlayer->geometryType() == QGis::Line )
239  return QgsLayerItem::iconLine();
240  else if ( vlayer->geometryType() == QGis::Polygon )
241  return QgsLayerItem::iconPolygon();
242  else if ( vlayer->geometryType() == QGis::NoGeometry )
243  return QgsLayerItem::iconTable();
244  }
245  return QgsLayerItem::iconDefault();
246  }
247  }
248  else if ( role == Qt::CheckStateRole )
249  {
251  return QVariant();
252 
253  if ( QgsLayerTree::isLayer( node ) )
254  {
255  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
256  if ( nodeLayer->layer() && nodeLayer->layer()->type() == QgsMapLayer::VectorLayer )
257  {
258  if ( qobject_cast<QgsVectorLayer*>( nodeLayer->layer() )->geometryType() == QGis::NoGeometry )
259  return QVariant(); // do not show checkbox for non-spatial tables
260  }
261  return nodeLayer->isVisible();
262  }
263  else if ( QgsLayerTree::isGroup( node ) )
264  {
265  QgsLayerTreeGroup* nodeGroup = QgsLayerTree::toGroup( node );
266  return nodeGroup->isVisible();
267  }
268  }
269  else if ( role == Qt::FontRole )
270  {
271  QFont f( QgsLayerTree::isLayer( node ) ? mFontLayer : ( QgsLayerTree::isGroup( node ) ? mFontGroup : QFont() ) );
272  if ( node->customProperty( "embedded" ).toInt() )
273  f.setItalic( true );
274  if ( index == mCurrentIndex )
275  f.setUnderline( true );
276  return f;
277  }
278  else if ( role == Qt::ToolTipRole )
279  {
280  if ( QgsLayerTree::isLayer( node ) )
281  {
282  if ( QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer() )
283  return layer->publicSource();
284  }
285  }
286 
287  return QVariant();
288 }
289 
290 Qt::ItemFlags QgsLayerTreeModel::flags( const QModelIndex& index ) const
291 {
292  if ( !index.isValid() )
293  {
294  Qt::ItemFlags rootFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
295  if ( testFlag( AllowNodeReorder ) )
296  rootFlags |= Qt::ItemIsDropEnabled;
297  return rootFlags;
298  }
299 
300  if ( QgsLayerTreeModelLegendNode* symn = index2legendNode( index ) )
301  {
302  Qt::ItemFlags f = symn->flags();
304  f &= ~Qt::ItemIsUserCheckable;
305  return f;
306  }
307 
308  Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
309 
310  if ( testFlag( AllowNodeRename ) )
311  f |= Qt::ItemIsEditable;
312 
313  QgsLayerTreeNode* node = index2node( index );
314  bool isEmbedded = node->customProperty( "embedded" ).toInt();
315 
316  if ( testFlag( AllowNodeReorder ) )
317  {
318  // only root embedded nodes can be reordered
319  if ( !isEmbedded || ( isEmbedded && node->parent() && !node->parent()->customProperty( "embedded" ).toInt() ) )
320  f |= Qt::ItemIsDragEnabled;
321  }
322 
324  f |= Qt::ItemIsUserCheckable;
325 
326  if ( testFlag( AllowNodeReorder ) && QgsLayerTree::isGroup( node ) && !isEmbedded )
327  f |= Qt::ItemIsDropEnabled;
328 
329  return f;
330 }
331 
332 bool QgsLayerTreeModel::setData( const QModelIndex& index, const QVariant& value, int role )
333 {
335  if ( sym )
336  {
337  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
338  return false;
339  bool res = sym->setData( value, role );
340  if ( res )
341  emit dataChanged( index, index );
342  return res;
343  }
344 
345  QgsLayerTreeNode* node = index2node( index );
346  if ( !node )
347  return QgsLayerTreeModel::setData( index, value, role );
348 
349  if ( role == Qt::CheckStateRole )
350  {
352  return false;
353 
354  if ( QgsLayerTree::isLayer( node ) )
355  {
356  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
357  layer->setVisible(( Qt::CheckState )value.toInt() );
358  return true;
359  }
360 
361  if ( QgsLayerTree::isGroup( node ) )
362  {
363  QgsLayerTreeGroup* group = QgsLayerTree::toGroup( node );
364  group->setVisible(( Qt::CheckState )value.toInt() );
365  return true;
366  }
367 
368  return true;
369  }
370  else if ( role == Qt::EditRole )
371  {
372  if ( !testFlag( AllowNodeRename ) )
373  return false;
374 
375  if ( QgsLayerTree::isLayer( node ) )
376  {
377  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
378  layer->setLayerName( value.toString() );
379  emit dataChanged( index, index );
380  }
381  else if ( QgsLayerTree::isGroup( node ) )
382  {
383  QgsLayerTree::toGroup( node )->setName( value.toString() );
384  emit dataChanged( index, index );
385  }
386  }
387 
388  return QAbstractItemModel::setData( index, value, role );
389 }
390 
392 {
393  if ( !node->parent() )
394  return QModelIndex(); // this is the only root item -> invalid index
395  QModelIndex parentIndex = node2index( node->parent() );
396 
397  int row = node->parent()->children().indexOf( node );
398  Q_ASSERT( row >= 0 );
399  return index( row, 0, parentIndex );
400 }
401 
402 
404 {
405  if ( !child->parent() )
406  return false;
407 
408  if ( child->parent() == node )
409  return true;
410 
411  return _isChildOfNode( child->parent(), node );
412 }
413 
414 static bool _isChildOfNodes( QgsLayerTreeNode* child, QList<QgsLayerTreeNode*> nodes )
415 {
416  foreach ( QgsLayerTreeNode* n, nodes )
417  {
418  if ( _isChildOfNode( child, n ) )
419  return true;
420  }
421  return false;
422 }
423 
424 
425 QList<QgsLayerTreeNode*> QgsLayerTreeModel::indexes2nodes( const QModelIndexList& list, bool skipInternal ) const
426 {
427  QList<QgsLayerTreeNode*> nodes;
428  foreach ( QModelIndex index, list )
429  {
430  QgsLayerTreeNode* node = index2node( index );
431  if ( !node )
432  continue;
433 
434  nodes << node;
435  }
436 
437  if ( !skipInternal )
438  return nodes;
439 
440  // remove any children of nodes if both parent node and children are selected
441  QList<QgsLayerTreeNode*> nodesFinal;
442  foreach ( QgsLayerTreeNode* node, nodes )
443  {
444  if ( !_isChildOfNodes( node, nodes ) )
445  nodesFinal << node;
446  }
447 
448  return nodesFinal;
449 }
450 
451 bool QgsLayerTreeModel::isIndexSymbologyNode( const QModelIndex& index ) const
452 {
453  return index2legendNode( index ) != 0;
454 }
455 
457 {
458  QgsLayerTreeModelLegendNode* symNode = index2legendNode( index );
459  return symNode ? symNode->parent() : 0;
460 }
461 
462 QList<QgsLayerTreeModelLegendNode*> QgsLayerTreeModel::layerLegendNodes( QgsLayerTreeLayer* nodeLayer )
463 {
464  return mLegendNodes.value( nodeLayer );
465 }
466 
468 {
469  return mRootNode;
470 }
471 
473 {
474  beginResetModel();
475 
477 
478  Q_ASSERT( mLegendNodes.isEmpty() );
479  Q_ASSERT( mOriginalLegendNodes.isEmpty() );
480 
481  mRootNode = newRootGroup;
482 
483  endResetModel();
484 
486 }
487 
489 {
490  // update title
491  QModelIndex idx = node2index( nodeLayer );
492  emit dataChanged( idx, idx );
493 
494  // update children
495  int oldNodeCount = rowCount( idx );
496  beginRemoveRows( idx, 0, oldNodeCount - 1 );
497  removeLegendFromLayer( nodeLayer );
498  endRemoveRows();
499 
500  addLegendToLayer( nodeLayer );
501  int newNodeCount = rowCount( idx );
502 
503  // automatic collapse of legend nodes - useful if a layer has many legend nodes
504  if ( mAutoCollapseLegendNodesCount != -1 && oldNodeCount != newNodeCount && newNodeCount >= mAutoCollapseLegendNodesCount )
505  nodeLayer->setExpanded( false );
506 }
507 
509 {
510  return mCurrentIndex;
511 }
512 
513 void QgsLayerTreeModel::setCurrentIndex( const QModelIndex& currentIndex )
514 {
515  QModelIndex oldIndex = mCurrentIndex;
517 
518  if ( oldIndex.isValid() )
519  emit dataChanged( oldIndex, oldIndex );
520  if ( currentIndex.isValid() )
521  emit dataChanged( currentIndex, currentIndex );
522 }
523 
524 
525 void QgsLayerTreeModel::setLayerTreeNodeFont( int nodeType, const QFont& font )
526 {
527  if ( nodeType == QgsLayerTreeNode::NodeGroup )
528  {
529  if ( mFontGroup != font )
530  {
531  mFontGroup = font;
533  }
534  }
535  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
536  {
537  if ( mFontLayer != font )
538  {
539  mFontLayer = font;
541  }
542  }
543  else
544  {
545  QgsDebugMsg( "invalid node type" );
546  }
547 }
548 
549 
550 QFont QgsLayerTreeModel::layerTreeNodeFont( int nodeType ) const
551 {
552  if ( nodeType == QgsLayerTreeNode::NodeGroup )
553  return mFontGroup;
554  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
555  return mFontLayer;
556  else
557  {
558  QgsDebugMsg( "invalid node type" );
559  return QFont();
560  }
561 }
562 
563 void QgsLayerTreeModel::setLegendFilterByScale( double scaleDenominator )
564 {
565  mLegendFilterByScale = scaleDenominator;
566 
567  // this could be later done in more efficient way
568  // by just updating active legend nodes, without refreshing original legend nodes
569  foreach ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
570  refreshLayerLegend( nodeLayer );
571 }
572 
573 void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
574 {
575  Q_ASSERT( node );
576  beginInsertRows( node2index( node ), indexFrom, indexTo );
577 }
578 
579 static QList<QgsLayerTreeLayer*> _layerNodesInSubtree( QgsLayerTreeNode* node, int indexFrom, int indexTo )
580 {
581  QList<QgsLayerTreeNode*> children = node->children();
582  QList<QgsLayerTreeLayer*> newLayerNodes;
583  for ( int i = indexFrom; i <= indexTo; ++i )
584  {
585  QgsLayerTreeNode* child = children.at( i );
586  if ( QgsLayerTree::isLayer( child ) )
587  newLayerNodes << QgsLayerTree::toLayer( child );
588  else if ( QgsLayerTree::isGroup( child ) )
589  newLayerNodes << QgsLayerTree::toGroup( child )->findLayers();
590  }
591  return newLayerNodes;
592 }
593 
594 void QgsLayerTreeModel::nodeAddedChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
595 {
596  Q_ASSERT( node );
597 
598  endInsertRows();
599 
600  foreach ( QgsLayerTreeLayer* newLayerNode, _layerNodesInSubtree( node, indexFrom, indexTo ) )
601  connectToLayer( newLayerNode );
602 }
603 
604 void QgsLayerTreeModel::nodeWillRemoveChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
605 {
606  Q_ASSERT( node );
607 
608  beginRemoveRows( node2index( node ), indexFrom, indexTo );
609 
610  // disconnect from layers and remove their legend
611  foreach ( QgsLayerTreeLayer* nodeLayer, _layerNodesInSubtree( node, indexFrom, indexTo ) )
612  disconnectFromLayer( nodeLayer );
613 }
614 
616 {
617  endRemoveRows();
618 }
619 
621 {
622  Q_ASSERT( node );
623 
624  QModelIndex index = node2index( node );
625  emit dataChanged( index, index );
626 }
627 
628 
630 {
631  if ( QgsLayerTree::isLayer( node ) && key == "showFeatureCount" )
633 }
634 
635 
637 {
638  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
639  if ( !nodeLayer )
640  return;
641 
642  // deffered connection to the layer
643  connectToLayer( nodeLayer );
644 }
645 
647 {
648  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
649  if ( !nodeLayer )
650  return;
651 
652  disconnectFromLayer( nodeLayer );
653 
654  // wait for the layer to appear again
655  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
656 }
657 
659 {
660  if ( !testFlag( ShowLegend ) )
661  return;
662 
663  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
664  if ( !layer )
665  return;
666 
667  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
668  if ( !nodeLayer )
669  return;
670 
671  refreshLayerLegend( nodeLayer );
672 }
673 
675 {
676  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
677  if ( !layer )
678  return;
679 
680  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
681  if ( !nodeLayer )
682  return;
683 
684  QModelIndex index = node2index( nodeLayer );
685  emit dataChanged( index, index );
686 
687  if ( nodeLayer->customProperty( "showFeatureCount" ).toInt() )
688  refreshLayerLegend( nodeLayer );
689 }
690 
691 
693 {
694  QgsLayerTreeModelLegendNode* legendNode = qobject_cast<QgsLayerTreeModelLegendNode*>( sender() );
695  if ( !legendNode )
696  return;
697 
698  QModelIndex index = legendNode2index( legendNode );
699  emit dataChanged( index, index );
700 }
701 
702 
704 {
705  if ( mLegendNodes.contains( nodeLayer ) )
706  {
707  qDeleteAll( mOriginalLegendNodes[nodeLayer] );
708  mOriginalLegendNodes.remove( nodeLayer );
709  mLegendNodes.remove( nodeLayer );
710  }
711 }
712 
713 
715 {
716  if ( !nodeL->layer() )
717  return;
718 
719  QgsMapLayerLegend* layerLegend = nodeL->layer()->legend();
720  if ( !layerLegend )
721  return;
722 
723  QList<QgsLayerTreeModelLegendNode*> lstNew = layerLegend->createLayerTreeModelLegendNodes( nodeL );
724 
725  // apply filtering defined in layer node's custom properties (reordering, filtering, custom labels)
727 
728  QList<QgsLayerTreeModelLegendNode*> filteredLstNew = filterLegendNodes( lstNew );
729 
730  beginInsertRows( node2index( nodeL ), 0, filteredLstNew.count() - 1 );
731 
732  foreach ( QgsLayerTreeModelLegendNode* n, lstNew )
733  {
734  n->setParent( this );
735  connect( n, SIGNAL( dataChanged() ), this, SLOT( legendNodeDataChanged() ) );
736  }
737 
738  mOriginalLegendNodes[nodeL] = lstNew;
739  mLegendNodes[nodeL] = filteredLstNew;
740 
741  endInsertRows();
742 }
743 
744 
746 {
747  if ( !nodeLayer->layer() )
748  {
749  // in order to connect to layer, we need to have it loaded.
750  // keep an eye on the layer ID: once loaded, we will use it
751  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
752  return;
753  }
754 
755  // watch if the layer is getting removed
756  connect( nodeLayer, SIGNAL( layerWillBeUnloaded() ), this, SLOT( nodeLayerWillBeUnloaded() ) );
757 
758  if ( testFlag( ShowLegend ) )
759  {
760  addLegendToLayer( nodeLayer );
761 
762  // automatic collapse of legend nodes - useful if a layer has many legend nodes
763  if ( !mRootNode->customProperty( "loading" ).toBool() )
764  {
766  nodeLayer->setExpanded( false );
767  }
768  }
769 
770  QgsMapLayer* layer = nodeLayer->layer();
771  connect( layer, SIGNAL( legendChanged() ), this, SLOT( layerLegendChanged() ), Qt::UniqueConnection );
772 
773  if ( layer->type() == QgsMapLayer::VectorLayer )
774  {
775  // using unique connection because there may be temporarily more nodes for a layer than just one
776  // which would create multiple connections, however disconnect() would disconnect all multiple connections
777  // even if we wanted to disconnect just one connection in each call.
778  connect( layer, SIGNAL( editingStarted() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
779  connect( layer, SIGNAL( editingStopped() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
780  connect( layer, SIGNAL( layerModified() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
781  connect( layer, SIGNAL( layerNameChanged() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
782  }
783 }
784 
785 // try to find out if the layer ID is present in the tree multiple times
786 static int _numLayerCount( QgsLayerTreeGroup* group, const QString& layerId )
787 {
788  int count = 0;
789  foreach ( QgsLayerTreeNode* child, group->children() )
790  {
791  if ( QgsLayerTree::isLayer( child ) )
792  {
793  if ( QgsLayerTree::toLayer( child )->layerId() == layerId )
794  count++;
795  }
796  else if ( QgsLayerTree::isGroup( child ) )
797  {
798  count += _numLayerCount( QgsLayerTree::toGroup( child ), layerId );
799  }
800  }
801  return count;
802 }
803 
805 {
806  disconnect( nodeLayer, 0, this, 0 ); // disconnect from delayed load of layer
807 
808  if ( !nodeLayer->layer() )
809  return; // we were never connected
810 
811  if ( testFlag( ShowLegend ) )
812  {
813  removeLegendFromLayer( nodeLayer );
814  }
815 
816  if ( _numLayerCount( mRootNode, nodeLayer->layerId() ) == 1 )
817  {
818  // last instance of the layer in the tree: disconnect from all signals from layer!
819  disconnect( nodeLayer->layer(), 0, this, 0 );
820  }
821 }
822 
824 {
825  foreach ( QgsLayerTreeNode* node, parentGroup->children() )
826  {
827  if ( QgsLayerTree::isGroup( node ) )
829  else if ( QgsLayerTree::isLayer( node ) )
831  }
832 }
833 
835 {
836  foreach ( QgsLayerTreeNode* node, parentGroup->children() )
837  {
838  if ( QgsLayerTree::isGroup( node ) )
840  else if ( QgsLayerTree::isLayer( node ) )
842  }
843 }
844 
846 {
847  Q_ASSERT( mRootNode );
848 
849  connect( mRootNode, SIGNAL( willAddChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillAddChildren( QgsLayerTreeNode*, int, int ) ) );
850  connect( mRootNode, SIGNAL( addedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeAddedChildren( QgsLayerTreeNode*, int, int ) ) );
851  connect( mRootNode, SIGNAL( willRemoveChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillRemoveChildren( QgsLayerTreeNode*, int, int ) ) );
852  connect( mRootNode, SIGNAL( removedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeRemovedChildren() ) );
853  connect( mRootNode, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
854 
855  connect( mRootNode, SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ), this, SLOT( nodeCustomPropertyChanged( QgsLayerTreeNode*, QString ) ) );
856 
858 }
859 
861 {
862  disconnect( mRootNode, 0, this, 0 );
863 
865 }
866 
867 void QgsLayerTreeModel::recursivelyEmitDataChanged( const QModelIndex& idx )
868 {
869  QgsLayerTreeNode* node = index2node( idx );
870  if ( !node )
871  return;
872 
873  int count = node->children().count();
874  if ( count == 0 )
875  return;
876  emit dataChanged( index( 0, 0, idx ), index( count - 1, 0, idx ) );
877  for ( int i = 0; i < count; ++i )
878  recursivelyEmitDataChanged( index( i, 0, idx ) );
879 }
880 
881 
883 {
884  return Qt::MoveAction;
885 }
886 
887 QStringList QgsLayerTreeModel::mimeTypes() const
888 {
889  QStringList types;
890  types << "application/qgis.layertreemodeldata";
891  return types;
892 }
893 
894 
895 QMimeData* QgsLayerTreeModel::mimeData( const QModelIndexList& indexes ) const
896 {
897  QList<QgsLayerTreeNode*> nodesFinal = indexes2nodes( indexes, true );
898 
899  if ( nodesFinal.count() == 0 )
900  return 0;
901 
902  QMimeData *mimeData = new QMimeData();
903 
904  QDomDocument doc;
905  QDomElement rootElem = doc.createElement( "layer_tree_model_data" );
906  foreach ( QgsLayerTreeNode* node, nodesFinal )
907  node->writeXML( rootElem );
908  doc.appendChild( rootElem );
909  QString txt = doc.toString();
910 
911  mimeData->setData( "application/qgis.layertreemodeldata", txt.toUtf8() );
912  return mimeData;
913 }
914 
915 bool QgsLayerTreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
916 {
917  if ( action == Qt::IgnoreAction )
918  return true;
919 
920  if ( !data->hasFormat( "application/qgis.layertreemodeldata" ) )
921  return false;
922 
923  if ( column > 0 )
924  return false;
925 
926  QgsLayerTreeNode* nodeParent = index2node( parent );
927  if ( !QgsLayerTree::isGroup( nodeParent ) )
928  return false;
929 
930  QByteArray encodedData = data->data( "application/qgis.layertreemodeldata" );
931 
932  QDomDocument doc;
933  if ( !doc.setContent( QString::fromUtf8( encodedData ) ) )
934  return false;
935 
936  QDomElement rootElem = doc.documentElement();
937  if ( rootElem.tagName() != "layer_tree_model_data" )
938  return false;
939 
940  QList<QgsLayerTreeNode*> nodes;
941 
942  QDomElement elem = rootElem.firstChildElement();
943  while ( !elem.isNull() )
944  {
946  if ( node )
947  nodes << node;
948 
949  elem = elem.nextSiblingElement();
950  }
951 
952  if ( nodes.count() == 0 )
953  return false;
954 
955  if ( parent.isValid() && row == -1 )
956  row = 0; // if dropped directly onto group item, insert at first position
957 
958  QgsLayerTree::toGroup( nodeParent )->insertChildNodes( row, nodes );
959 
960  return true;
961 }
962 
963 bool QgsLayerTreeModel::removeRows( int row, int count, const QModelIndex& parent )
964 {
965  QgsLayerTreeNode* parentNode = index2node( parent );
966  if ( QgsLayerTree::isGroup( parentNode ) )
967  {
968  QgsLayerTree::toGroup( parentNode )->removeChildren( row, count );
969  return true;
970  }
971  return false;
972 }
973 
974 void QgsLayerTreeModel::setFlags( QgsLayerTreeModel::Flags f )
975 {
976  mFlags = f;
977 }
978 
980 {
981  if ( on )
982  mFlags |= f;
983  else
984  mFlags &= ~f;
985 }
986 
987 QgsLayerTreeModel::Flags QgsLayerTreeModel::flags() const
988 {
989  return mFlags;
990 }
991 
993 {
994  return mFlags.testFlag( f );
995 }
996 
997 
999 {
1000  static QIcon icon;
1001 
1002  if ( icon.isNull() )
1003  icon = QgsApplication::getThemeIcon( "/mActionFolder.png" );
1004 
1005  return icon;
1006 }
1007 
1008 QList<QgsLayerTreeModelLegendNode*> QgsLayerTreeModel::filterLegendNodes( const QList<QgsLayerTreeModelLegendNode*>& nodes )
1009 {
1010  QList<QgsLayerTreeModelLegendNode*> filtered;
1011  foreach ( QgsLayerTreeModelLegendNode* node, nodes )
1012  {
1013  if ( mLegendFilterByScale > 0 && !node->isScaleOK( mLegendFilterByScale ) )
1014  continue;
1015 
1016  filtered << node;
1017  }
1018  return filtered;
1019 }
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
static const QIcon & iconDefault()
Definition: qgsdataitem.cpp:93
void nodeCustomPropertyChanged(QgsLayerTreeNode *node, const QString &key)
void addLegendToLayer(QgsLayerTreeLayer *nodeL)
static const QIcon & iconPoint()
Definition: qgsdataitem.cpp:43
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:36
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)
QgsLayerTreeLayer * findLayer(const QString &layerId)
Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tr...
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:63
QgsLayerTreeLayer * parent() const
Return pointer to the parent layer node.
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.
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)
QgsLayerTreeGroup * rootGroup()
Return pointer to the root node of the layer tree. Always a non-null pointer.
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:83
void disconnectFromLayers(QgsLayerTreeGroup *parentGroup)
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
void setName(const QString &n)
Set group's name.
void setFlags(Flags f)
Set OR-ed combination of model flags.
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.
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.
QgsMapLayerLegend * legend() const
Can be null.
static const QIcon & iconTable()
Definition: qgsdataitem.cpp:73
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...
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
static const QIcon & iconLine()
Definition: qgsdataitem.cpp:53
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).
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.
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)