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