QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgslayertreeview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayertreeview.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 "qgslayertreeview.h"
17 
18 #include "qgslayertree.h"
19 #include "qgslayertreemodel.h"
22 #include "qgsmaplayer.h"
23 
24 #include <QMenu>
25 #include <QContextMenuEvent>
26 
28  : QTreeView( parent )
29  , mDefaultActions( 0 )
30  , mMenuProvider( 0 )
31 {
32  setHeaderHidden( true );
33 
34  setDragEnabled( true );
35  setAcceptDrops( true );
36  setDropIndicatorShown( true );
37  setEditTriggers( EditKeyPressed );
38  setExpandsOnDoubleClick( false ); // normally used for other actions
39 
40  setSelectionMode( ExtendedSelection );
41 
42  connect( this, SIGNAL( collapsed( QModelIndex ) ), this, SLOT( updateExpandedStateToNode( QModelIndex ) ) );
43  connect( this, SIGNAL( expanded( QModelIndex ) ), this, SLOT( updateExpandedStateToNode( QModelIndex ) ) );
44 }
45 
47 {
48  delete mMenuProvider;
49 }
50 
51 void QgsLayerTreeView::setModel( QAbstractItemModel* model )
52 {
53  if ( !qobject_cast<QgsLayerTreeModel*>( model ) )
54  return;
55 
56  connect( model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( modelRowsInserted( QModelIndex, int, int ) ) );
57  connect( model, SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( modelRowsRemoved() ) );
58 
59  QTreeView::setModel( model );
60 
61  connect( layerTreeModel()->rootGroup(), SIGNAL( expandedChanged( QgsLayerTreeNode*, bool ) ), this, SLOT( onExpandedChanged( QgsLayerTreeNode*, bool ) ) );
62 
63  connect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SLOT( onCurrentChanged() ) );
64 
65  connect( layerTreeModel(), SIGNAL( modelReset() ), this, SLOT( onModelReset() ) );
66 
68 }
69 
71 {
72  return qobject_cast<QgsLayerTreeModel*>( model() );
73 }
74 
76 {
77  if ( !mDefaultActions )
79  return mDefaultActions;
80 }
81 
83 {
84  delete mMenuProvider;
86 }
87 
89 {
90  return layerForIndex( currentIndex() );
91 }
92 
94 {
95  if ( !layer )
96  {
97  setCurrentIndex( QModelIndex() );
98  return;
99  }
100 
101  QgsLayerTreeLayer* nodeLayer = layerTreeModel()->rootGroup()->findLayer( layer->id() );
102  if ( !nodeLayer )
103  return;
104 
105  setCurrentIndex( layerTreeModel()->node2index( nodeLayer ) );
106 }
107 
108 
109 void QgsLayerTreeView::contextMenuEvent( QContextMenuEvent *event )
110 {
111  if ( !mMenuProvider )
112  return;
113 
114  QModelIndex idx = indexAt( event->pos() );
115  if ( !idx.isValid() )
116  setCurrentIndex( QModelIndex() );
117 
118  QMenu* menu = mMenuProvider->createContextMenu();
119  if ( menu && menu->actions().count() != 0 )
120  menu->exec( mapToGlobal( event->pos() ) );
121  delete menu;
122 }
123 
124 
125 void QgsLayerTreeView::modelRowsInserted( QModelIndex index, int start, int end )
126 {
127  QgsLayerTreeNode* parentNode = layerTreeModel()->index2node( index );
128  if ( !parentNode )
129  return;
130 
131  if ( QgsLayerTree::isLayer( parentNode ) )
132  return; // layers have only symbology nodes (no expanded/collapsed handling)
133 
134  QList<QgsLayerTreeNode*> children = parentNode->children();
135  for ( int i = start; i <= end; ++i )
136  {
137  updateExpandedStateFromNode( children[i] );
138  }
139 
140  // make sure we still have correct current layer
142 }
143 
145 {
146  // make sure we still have correct current layer
148 }
149 
151 {
152  QgsLayerTreeNode* node = layerTreeModel()->index2node( index );
153  if ( !node )
154  return;
155 
156  node->setExpanded( isExpanded( index ) );
157 }
158 
160 {
161  QgsMapLayer* layerCurrent = layerForIndex( currentIndex() );
162  QString layerCurrentID = layerCurrent ? layerCurrent->id() : QString();
163  if ( mCurrentLayerID == layerCurrentID )
164  return;
165 
166  // update the current index in model (the item will be underlined)
167  QModelIndex nodeLayerIndex;
168  if ( layerCurrent )
169  {
170  QgsLayerTreeLayer* nodeLayer = layerTreeModel()->rootGroup()->findLayer( layerCurrentID );
171  nodeLayerIndex = layerTreeModel()->node2index( nodeLayer );
172  }
173  layerTreeModel()->setCurrentIndex( nodeLayerIndex );
174 
175  mCurrentLayerID = layerCurrentID;
176  emit currentLayerChanged( layerCurrent );
177 }
178 
180 {
181  QModelIndex idx = layerTreeModel()->node2index( node );
182  if ( isExpanded( idx ) != expanded )
183  setExpanded( idx, expanded );
184 }
185 
187 {
189 }
190 
192 {
193  QModelIndex idx = layerTreeModel()->node2index( node );
194  setExpanded( idx, node->isExpanded() );
195 
196  foreach ( QgsLayerTreeNode* child, node->children() )
198 }
199 
201 {
202  QgsLayerTreeNode* node = layerTreeModel()->index2node( index );
203  if ( node )
204  {
205  if ( QgsLayerTree::isLayer( node ) )
206  return QgsLayerTree::toLayer( node )->layer();
207  }
208  else
209  {
210  // possibly a legend node
212  if ( legendNode )
213  return legendNode->layerNode()->layer();
214  }
215 
216  return 0;
217 }
218 
220 {
221  return layerTreeModel()->index2node( selectionModel()->currentIndex() );
222 }
223 
225 {
226  QgsLayerTreeNode* node = currentNode();
227  if ( QgsLayerTree::isGroup( node ) )
228  return QgsLayerTree::toGroup( node );
229  else if ( QgsLayerTree::isLayer( node ) )
230  {
231  QgsLayerTreeNode* parent = node->parent();
232  if ( QgsLayerTree::isGroup( parent ) )
233  return QgsLayerTree::toGroup( parent );
234  }
235 
236  if ( QgsLayerTreeModelLegendNode* legendNode = layerTreeModel()->index2legendNode( selectionModel()->currentIndex() ) )
237  {
238  QgsLayerTreeLayer* parent = legendNode->layerNode();
239  if ( QgsLayerTree::isGroup( parent->parent() ) )
240  return QgsLayerTree::toGroup( parent->parent() );
241  }
242 
243  return 0;
244 }
245 
246 QList<QgsLayerTreeNode*> QgsLayerTreeView::selectedNodes( bool skipInternal ) const
247 {
248  return layerTreeModel()->indexes2nodes( selectionModel()->selectedIndexes(), skipInternal );
249 }
250 
251 QList<QgsLayerTreeLayer*> QgsLayerTreeView::selectedLayerNodes() const
252 {
253  QList<QgsLayerTreeLayer*> layerNodes;
254  foreach ( QgsLayerTreeNode* node, selectedNodes() )
255  {
256  if ( QgsLayerTree::isLayer( node ) )
257  layerNodes << QgsLayerTree::toLayer( node );
258  }
259  return layerNodes;
260 }
261 
262 QList<QgsMapLayer*> QgsLayerTreeView::selectedLayers() const
263 {
264  QList<QgsMapLayer*> list;
265  foreach ( QgsLayerTreeLayer* node, selectedLayerNodes() )
266  {
267  if ( node->layer() )
268  list << node->layer();
269  }
270  return list;
271 }
272 
273 
274 void QgsLayerTreeView::refreshLayerSymbology( const QString& layerId )
275 {
276  QgsLayerTreeLayer* nodeLayer = layerTreeModel()->rootGroup()->findLayer( layerId );
277  if ( nodeLayer )
278  layerTreeModel()->refreshLayerLegend( nodeLayer );
279 }
Layer tree group node serves as a container for layers and further groups.
QgsLayerTreeModel * layerTreeModel() const
Get access to the model casted to QgsLayerTreeModel.
static unsigned index
Base class for all map layer types.
Definition: qgsmaplayer.h:48
Implementation of this interface can be implemented to allow QgsLayerTreeView instance to provide cus...
QgsMapLayer * currentLayer() const
Get currently selected layer. May be null.
void setCurrentIndex(const QModelIndex &currentIndex)
Set index of the current item. May be used by view. Item marked as current is underlined.
QgsLayerTreeViewMenuProvider * mMenuProvider
Context menu provider. Owned by the view.
QList< QgsLayerTreeNode * > indexes2nodes(const QModelIndexList &list, bool skipInternal=false) const
Convert a list of indexes to a list of layer tree nodes.
QgsLayerTreeGroup * rootGroup() const
Return pointer to the root node of the layer tree. Always a non-null pointer.
void refreshLayerSymbology(const QString &layerId)
Force refresh of layer symbology. Normally not needed as the changes of layer's renderer are monitore...
QgsMapLayer * layer() const
QgsLayerTreeViewMenuProvider * menuProvider() const
Return pointer to the context menu provider. May be null.
virtual void setModel(QAbstractItemModel *model)
Overridden setModel() from base class. Only QgsLayerTreeModel is an acceptable model.
QgsLayerTreeNode * currentNode() const
Get current node. May be null.
QList< QgsMapLayer * > selectedLayers() const
Get list of selected layers.
QgsLayerTreeViewDefaultActions * defaultActions()
Get access to the default actions that may be used with the tree view.
QList< QgsLayerTreeNode * > selectedNodes(bool skipInternal=false) const
Return list of selected nodes.
virtual QMenu * createContextMenu()=0
Return a newly created menu instance (or null pointer on error)
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
QString mCurrentLayerID
Keeps track of current layer ID (to check when to emit signal about change of current layer) ...
The QgsLayerTreeViewDefaultActions class serves as a factory of actions that can be used together wit...
The QgsLayerTreeModel class is model implementation for Qt item views framework.
void modelRowsInserted(QModelIndex index, int start, int end)
void contextMenuEvent(QContextMenuEvent *event)
QgsLayerTreeGroup * currentGroupNode() const
Get current group node. If a layer is current node, the function will return parent group...
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Return legend node for given index.
QgsLayerTreeNode * parent()
Get pointer to the parent. If parent is a null pointer, the node is a root node.
QgsLayerTreeLayer * layerNode() const
Return pointer to the parent layer node.
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
bool isExpanded() const
Return whether the node should be shown as expanded or collapsed in GUI.
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 currentLayerChanged(QgsMapLayer *layer)
Emitted when a current layer is changed.
void refreshLayerLegend(QgsLayerTreeLayer *nodeLayer)
Force a refresh of legend nodes of a layer node.
QgsLayerTreeViewDefaultActions * mDefaultActions
helper class with default actions. Lazily initialized.
QList< QgsLayerTreeLayer * > selectedLayerNodes() const
Return list of selected nodes filtered to just layer nodes.
void setExpanded(bool expanded)
Set whether the node should be shown as expanded or collapsed in GUI.
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 updateExpandedStateFromNode(QgsLayerTreeNode *node)
void onExpandedChanged(QgsLayerTreeNode *node, bool expanded)
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
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
QgsLayerTreeLayer * findLayer(const QString &layerId) const
Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tr...
QgsLayerTreeView(QWidget *parent=0)
void setCurrentLayer(QgsMapLayer *layer)
Set currently selected layer. Null pointer will deselect any layer.
void setMenuProvider(QgsLayerTreeViewMenuProvider *menuProvider)
Set provider for context menu. Takes ownership of the instance.
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Return layer tree node for given index.
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:34
QgsMapLayer * layerForIndex(const QModelIndex &index) const
void updateExpandedStateToNode(QModelIndex index)
Layer tree node points to a map layer.