QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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  for ( int i = start; i <= end; ++i )
135  {
136  updateExpandedStateFromNode( parentNode->children()[i] );
137  }
138 
139  // make sure we still have correct current layer
141 }
142 
144 {
145  // make sure we still have correct current layer
147 }
148 
150 {
151  QgsLayerTreeNode* node = layerTreeModel()->index2node( index );
152  if ( !node )
153  return;
154 
155  node->setExpanded( isExpanded( index ) );
156 }
157 
159 {
160  QgsMapLayer* layerCurrent = layerForIndex( currentIndex() );
161  QModelIndex layerCurrentIndex = layerCurrent ? layerTreeModel()->node2index( layerTreeModel()->rootGroup()->findLayer( layerCurrent->id() ) ) : QModelIndex();
162  if ( mCurrentIndex == layerCurrentIndex )
163  return;
164 
165  layerTreeModel()->setCurrentIndex( layerCurrentIndex );
166 
167  mCurrentIndex = layerCurrentIndex;
168  emit currentLayerChanged( layerCurrent );
169 }
170 
172 {
173  QModelIndex idx = layerTreeModel()->node2index( node );
174  if ( isExpanded( idx ) != expanded )
175  setExpanded( idx, expanded );
176 }
177 
179 {
181 }
182 
184 {
185  QModelIndex idx = layerTreeModel()->node2index( node );
186  setExpanded( idx, node->isExpanded() );
187 
188  foreach ( QgsLayerTreeNode* child, node->children() )
190 }
191 
193 {
194  QgsLayerTreeNode* node = layerTreeModel()->index2node( index );
195  if ( node )
196  {
197  if ( QgsLayerTree::isLayer( node ) )
198  return QgsLayerTree::toLayer( node )->layer();
199  }
200  else
201  {
202  // possibly a legend node
204  if ( legendNode )
205  return legendNode->parent()->layer();
206  }
207 
208  return 0;
209 }
210 
212 {
213  return layerTreeModel()->index2node( selectionModel()->currentIndex() );
214 }
215 
217 {
218  QgsLayerTreeNode* node = currentNode();
219  if ( QgsLayerTree::isGroup( node ) )
220  return QgsLayerTree::toGroup( node );
221  else if ( QgsLayerTree::isLayer( node ) )
222  {
223  QgsLayerTreeNode* parent = node->parent();
224  if ( QgsLayerTree::isGroup( parent ) )
225  return QgsLayerTree::toGroup( parent );
226  }
227 
228  if ( QgsLayerTreeModelLegendNode* legendNode = layerTreeModel()->index2legendNode( selectionModel()->currentIndex() ) )
229  {
230  QgsLayerTreeLayer* parent = legendNode->parent();
231  if ( QgsLayerTree::isGroup( parent->parent() ) )
232  return QgsLayerTree::toGroup( parent->parent() );
233  }
234 
235  return 0;
236 }
237 
238 QList<QgsLayerTreeNode*> QgsLayerTreeView::selectedNodes( bool skipInternal ) const
239 {
240  return layerTreeModel()->indexes2nodes( selectionModel()->selectedIndexes(), skipInternal );
241 }
242 
243 QList<QgsLayerTreeLayer*> QgsLayerTreeView::selectedLayerNodes() const
244 {
245  QList<QgsLayerTreeLayer*> layerNodes;
246  foreach ( QgsLayerTreeNode* node, selectedNodes() )
247  {
248  if ( QgsLayerTree::isLayer( node ) )
249  layerNodes << QgsLayerTree::toLayer( node );
250  }
251  return layerNodes;
252 }
253 
254 QList<QgsMapLayer*> QgsLayerTreeView::selectedLayers() const
255 {
256  QList<QgsMapLayer*> list;
257  foreach ( QgsLayerTreeLayer* node, selectedLayerNodes() )
258  {
259  if ( node->layer() )
260  list << node->layer();
261  }
262  return list;
263 }
264 
265 
266 void QgsLayerTreeView::refreshLayerSymbology( const QString& layerId )
267 {
268  QgsLayerTreeLayer* nodeLayer = layerTreeModel()->rootGroup()->findLayer( layerId );
269  if ( nodeLayer )
270  layerTreeModel()->refreshLayerLegend( nodeLayer );
271 }
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.
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.
QgsLayerTreeLayer * findLayer(const QString &layerId)
Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tr...
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.
QgsLayerTreeLayer * parent() const
Return pointer to the parent layer node.
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
QgsLayerTreeGroup * rootGroup()
Return pointer to the root node of the layer tree. Always a non-null pointer.
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.
QPersistentModelIndex mCurrentIndex
Keeps track of current index (to check when to emit signal about change of current layer) ...
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.
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...
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.