QGIS API Documentation  2.12.0-Lyon
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 
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  {
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 
110 {
111  if ( !mMenuProvider )
112  return;
113 
114  QModelIndex idx = indexAt( event->pos() );
115  if ( !idx.isValid() )
117 
119  if ( menu && menu->actions().count() != 0 )
120  menu->exec( mapToGlobal( event->pos() ) );
121  delete menu;
122 }
123 
124 
125 void QgsLayerTreeView::modelRowsInserted( const 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  {
133  // if ShowLegendAsTree flag is enabled in model, we may need to expand some legend nodes
134  QStringList expandedNodeKeys = parentNode->customProperty( "expandedLegendNodes" ).toStringList();
135  if ( expandedNodeKeys.isEmpty() )
136  return;
137 
138  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, layerTreeModel()->layerLegendNodes( QgsLayerTree::toLayer( parentNode ) ) )
139  {
141  if ( expandedNodeKeys.contains( ruleKey ) )
142  setExpanded( layerTreeModel()->legendNode2index( legendNode ), true );
143  }
144  return;
145  }
146 
148  for ( int i = start; i <= end; ++i )
149  {
150  updateExpandedStateFromNode( children[i] );
151  }
152 
153  // make sure we still have correct current layer
155 }
156 
158 {
159  // make sure we still have correct current layer
161 }
162 
164 {
165  if ( QgsLayerTreeNode* node = layerTreeModel()->index2node( index ) )
166  {
167  node->setExpanded( isExpanded( index ) );
168  }
169  else if ( QgsLayerTreeModelLegendNode* node = layerTreeModel()->index2legendNode( index ) )
170  {
171  QString ruleKey = node->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
172  QStringList lst = node->layerNode()->customProperty( "expandedLegendNodes" ).toStringList();
173  bool expanded = isExpanded( index );
174  bool isInList = lst.contains( ruleKey );
175  if ( expanded && !isInList )
176  {
177  lst.append( ruleKey );
178  node->layerNode()->setCustomProperty( "expandedLegendNodes", lst );
179  }
180  else if ( !expanded && isInList )
181  {
182  lst.removeAll( ruleKey );
183  node->layerNode()->setCustomProperty( "expandedLegendNodes", lst );
184  }
185  }
186 }
187 
189 {
190  QgsMapLayer* layerCurrent = layerForIndex( currentIndex() );
191  QString layerCurrentID = layerCurrent ? layerCurrent->id() : QString();
192  if ( mCurrentLayerID == layerCurrentID )
193  return;
194 
195  // update the current index in model (the item will be underlined)
196  QModelIndex nodeLayerIndex;
197  if ( layerCurrent )
198  {
199  QgsLayerTreeLayer* nodeLayer = layerTreeModel()->rootGroup()->findLayer( layerCurrentID );
200  if ( nodeLayer )
201  nodeLayerIndex = layerTreeModel()->node2index( nodeLayer );
202  }
203  layerTreeModel()->setCurrentIndex( nodeLayerIndex );
204 
205  mCurrentLayerID = layerCurrentID;
206  emit currentLayerChanged( layerCurrent );
207 }
208 
210 {
211  QModelIndex idx = layerTreeModel()->node2index( node );
212  if ( isExpanded( idx ) != expanded )
213  setExpanded( idx, expanded );
214 }
215 
217 {
219 }
220 
222 {
223  QModelIndex idx = layerTreeModel()->node2index( node );
224  setExpanded( idx, node->isExpanded() );
225 
226  Q_FOREACH ( QgsLayerTreeNode* child, node->children() )
228 }
229 
231 {
232  QgsLayerTreeNode* node = layerTreeModel()->index2node( index );
233  if ( node )
234  {
235  if ( QgsLayerTree::isLayer( node ) )
236  return QgsLayerTree::toLayer( node )->layer();
237  }
238  else
239  {
240  // possibly a legend node
242  if ( legendNode )
243  return legendNode->layerNode()->layer();
244  }
245 
246  return 0;
247 }
248 
250 {
252 }
253 
255 {
256  QgsLayerTreeNode* node = currentNode();
257  if ( QgsLayerTree::isGroup( node ) )
258  return QgsLayerTree::toGroup( node );
259  else if ( QgsLayerTree::isLayer( node ) )
260  {
261  QgsLayerTreeNode* parent = node->parent();
262  if ( QgsLayerTree::isGroup( parent ) )
263  return QgsLayerTree::toGroup( parent );
264  }
265 
266  if ( QgsLayerTreeModelLegendNode* legendNode = layerTreeModel()->index2legendNode( selectionModel()->currentIndex() ) )
267  {
268  QgsLayerTreeLayer* parent = legendNode->layerNode();
269  if ( QgsLayerTree::isGroup( parent->parent() ) )
270  return QgsLayerTree::toGroup( parent->parent() );
271  }
272 
273  return 0;
274 }
275 
277 {
278  return layerTreeModel()->indexes2nodes( selectionModel()->selectedIndexes(), skipInternal );
279 }
280 
282 {
283  QList<QgsLayerTreeLayer*> layerNodes;
284  Q_FOREACH ( QgsLayerTreeNode* node, selectedNodes() )
285  {
286  if ( QgsLayerTree::isLayer( node ) )
287  layerNodes << QgsLayerTree::toLayer( node );
288  }
289  return layerNodes;
290 }
291 
293 {
294  QList<QgsMapLayer*> list;
295  Q_FOREACH ( QgsLayerTreeLayer* node, selectedLayerNodes() )
296  {
297  if ( node->layer() )
298  list << node->layer();
299  }
300  return list;
301 }
302 
303 
305 {
306  QgsLayerTreeLayer* nodeLayer = layerTreeModel()->rootGroup()->findLayer( layerId );
307  if ( nodeLayer )
308  layerTreeModel()->refreshLayerLegend( nodeLayer );
309 }
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
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:49
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 setCurrentIndex(const QModelIndex &index)
void setSelectionMode(QAbstractItemView::SelectionMode mode)
QgsLayerTreeGroup * rootGroup() const
Return pointer to the root node of the layer tree. Always a non-null pointer.
QItemSelectionModel * selectionModel() const
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
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
virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous)
void contextMenuEvent(QContextMenuEvent *event) override
void collapsed(const QModelIndex &index)
const QObjectList & children() const
bool contains(const QString &str, Qt::CaseSensitivity cs) const
QgsLayerTreeViewMenuProvider * menuProvider() const
Return pointer to the context menu provider. May be null.
QPoint mapToGlobal(const QPoint &pos) const
QgsLayerTreeNode * currentNode() const
Get current node. May be null.
QList< QgsMapLayer * > selectedLayers() const
Get list of selected layers.
void modelRowsInserted(const QModelIndex &index, int start, int end)
void rowsRemoved(const QModelIndex &parent, int start, int end)
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) ...
void setExpanded(const QModelIndex &index, bool expanded)
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.
bool isValid() const
void updateExpandedStateToNode(const QModelIndex &index)
void append(const T &value)
QModelIndex legendNode2index(QgsLayerTreeModelLegendNode *legendNode)
Return index for a given legend node.
QgsLayerTreeGroup * currentGroupNode() const
Get current group node. If a layer is current node, the function will return parent group...
virtual void rowsInserted(const QModelIndex &parent, int start, int end)
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Return legend node for given index.
bool isEmpty() const
QgsLayerTreeNode * parent()
Get pointer to the parent. If parent is a null pointer, the node is a root node.
int removeAll(const T &value)
QgsLayerTreeLayer * layerNode() const
Return pointer to the parent layer node.
void setEditTriggers(QFlags< QAbstractItemView::EditTrigger > triggers)
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.
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
bool isExpanded(const QModelIndex &index) const
QAction * exec()
void setAcceptDrops(bool on)
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.
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 setExpandsOnDoubleClick(bool enable)
const QPoint & pos() const
QStringList toStringList() const
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
void setHeaderHidden(bool hide)
virtual void setModel(QAbstractItemModel *model)
virtual QVariant data(int role) const =0
Return data associated with the item.
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
virtual QModelIndexList selectedIndexes() const
virtual void setModel(QAbstractItemModel *model) override
Overridden setModel() from base class. Only QgsLayerTreeModel is an acceptable model.
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 expanded(const QModelIndex &index)
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.
QAbstractItemModel * model() const
QModelIndex currentIndex() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QList< QAction * > actions() const
QObject * parent() const
QChar * data()
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:34
QString toString() const
virtual QModelIndex indexAt(const QPoint &point) const
void setDropIndicatorShown(bool enable)
QgsMapLayer * layerForIndex(const QModelIndex &index) const
void setDragEnabled(bool enable)
Layer tree node points to a map layer.