QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgslayertreegroup.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayertreegroup.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 "qgslayertreegroup.h"
17 
18 #include "qgslayertree.h"
19 #include "qgslayertreeutils.h"
20 
21 #include <QDomElement>
22 #include <QStringList>
23 
24 
25 QgsLayerTreeGroup::QgsLayerTreeGroup( const QString& name, Qt::CheckState checked )
26  : QgsLayerTreeNode( NodeGroup )
27  , mName( name )
28  , mChecked( checked )
29  , mChangingChildVisibility( false )
30 {
31  connect( this, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
32 }
33 
35  : QgsLayerTreeNode( other )
36  , mName( other.mName )
37  , mChecked( other.mChecked )
38  , mChangingChildVisibility( false )
39 {
40  connect( this, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
41 }
42 
43 
45 {
46  QgsLayerTreeGroup* grp = new QgsLayerTreeGroup( name );
47  insertChildNode( index, grp );
48  return grp;
49 }
50 
52 {
53  QgsLayerTreeGroup* grp = new QgsLayerTreeGroup( name );
54  addChildNode( grp );
55  return grp;
56 }
57 
59 {
60  QgsLayerTreeLayer* ll = new QgsLayerTreeLayer( layer );
61  insertChildNode( index, ll );
62  return ll;
63 }
64 
66 {
67  QgsLayerTreeLayer* ll = new QgsLayerTreeLayer( layer );
68  addChildNode( ll );
69  return ll;
70 }
71 
73 {
74  QList<QgsLayerTreeNode*> nodes;
75  nodes << node;
76  insertChildNodes( index, nodes );
77 }
78 
79 void QgsLayerTreeGroup::insertChildNodes( int index, QList<QgsLayerTreeNode*> nodes )
80 {
81  // low-level insert
82  insertChildrenPrivate( index, nodes );
83 
85 }
86 
88 {
89  insertChildNode( -1, node );
90 }
91 
93 {
94  int i = mChildren.indexOf( node );
95  if ( i >= 0 )
96  removeChildren( i, 1 );
97 }
98 
100 {
101  foreach ( QgsLayerTreeNode* child, mChildren )
102  {
103  if ( QgsLayerTree::isLayer( child ) )
104  {
105  QgsLayerTreeLayer* childLayer = QgsLayerTree::toLayer( child );
106  if ( childLayer->layer() == layer )
107  {
108  removeChildren( mChildren.indexOf( child ), 1 );
109  break;
110  }
111  }
112  }
113 }
114 
115 void QgsLayerTreeGroup::removeChildren( int from, int count )
116 {
117  removeChildrenPrivate( from, count );
118 
120 }
121 
123 {
124  // clean the layer tree by removing empty group
125  foreach ( QgsLayerTreeNode* treeNode, children() )
126  {
127  if ( treeNode->nodeType() == QgsLayerTreeNode::NodeGroup )
128  {
129  QgsLayerTreeGroup* treeGroup = qobject_cast<QgsLayerTreeGroup*>( treeNode );
130  if ( treeGroup->findLayerIds().count() == 0 )
131  removeChildNode( treeNode );
132  else
134  }
135  }
136 }
137 
139 {
140  removeChildren( 0, mChildren.count() );
141 }
142 
143 QgsLayerTreeLayer *QgsLayerTreeGroup::findLayer( const QString& layerId ) const
144 {
145  foreach ( QgsLayerTreeNode* child, mChildren )
146  {
147  if ( QgsLayerTree::isLayer( child ) )
148  {
149  QgsLayerTreeLayer* childLayer = QgsLayerTree::toLayer( child );
150  if ( childLayer->layerId() == layerId )
151  return childLayer;
152  }
153  else if ( QgsLayerTree::isGroup( child ) )
154  {
155  QgsLayerTreeLayer* res = QgsLayerTree::toGroup( child )->findLayer( layerId );
156  if ( res )
157  return res;
158  }
159  }
160  return 0;
161 }
162 
163 QList<QgsLayerTreeLayer*> QgsLayerTreeGroup::findLayers() const
164 {
165  QList<QgsLayerTreeLayer*> list;
166  foreach ( QgsLayerTreeNode* child, mChildren )
167  {
168  if ( QgsLayerTree::isLayer( child ) )
169  list << QgsLayerTree::toLayer( child );
170  else if ( QgsLayerTree::isGroup( child ) )
171  list << QgsLayerTree::toGroup( child )->findLayers();
172  }
173  return list;
174 }
175 
177 {
178  foreach ( QgsLayerTreeNode* child, mChildren )
179  {
180  if ( QgsLayerTree::isGroup( child ) )
181  {
182  QgsLayerTreeGroup* childGroup = QgsLayerTree::toGroup( child );
183  if ( childGroup->name() == name )
184  return childGroup;
185  else
186  {
187  QgsLayerTreeGroup* grp = childGroup->findGroup( name );
188  if ( grp )
189  return grp;
190  }
191  }
192  }
193  return 0;
194 }
195 
197 {
198  if ( element.tagName() != "layer-tree-group" )
199  return 0;
200 
201  QString name = element.attribute( "name" );
202  bool isExpanded = ( element.attribute( "expanded", "1" ) == "1" );
203  Qt::CheckState checked = QgsLayerTreeUtils::checkStateFromXml( element.attribute( "checked" ) );
204 
205  QgsLayerTreeGroup* groupNode = new QgsLayerTreeGroup( name, checked );
206  groupNode->setExpanded( isExpanded );
207 
208  groupNode->readCommonXML( element );
209 
210  groupNode->readChildrenFromXML( element );
211 
212  return groupNode;
213 }
214 
215 void QgsLayerTreeGroup::writeXML( QDomElement& parentElement )
216 {
217  QDomDocument doc = parentElement.ownerDocument();
218  QDomElement elem = doc.createElement( "layer-tree-group" );
219  elem.setAttribute( "name", mName );
220  elem.setAttribute( "expanded", mExpanded ? "1" : "0" );
221  elem.setAttribute( "checked", QgsLayerTreeUtils::checkStateToXml( mChecked ) );
222 
223  writeCommonXML( elem );
224 
225  foreach ( QgsLayerTreeNode* node, mChildren )
226  node->writeXML( elem );
227 
228  parentElement.appendChild( elem );
229 }
230 
231 void QgsLayerTreeGroup::readChildrenFromXML( QDomElement& element )
232 {
233  QList<QgsLayerTreeNode*> nodes;
234  QDomElement childElem = element.firstChildElement();
235  while ( !childElem.isNull() )
236  {
237  QgsLayerTreeNode* newNode = QgsLayerTreeNode::readXML( childElem );
238  if ( newNode )
239  nodes << newNode;
240 
241  childElem = childElem.nextSiblingElement();
242  }
243 
244  insertChildNodes( -1, nodes );
245 }
246 
247 QString QgsLayerTreeGroup::dump() const
248 {
249  QString header = QString( "GROUP: %1 visible=%2 expanded=%3\n" ).arg( name() ).arg( mChecked ).arg( mExpanded );
250  QStringList childrenDump;
251  foreach ( QgsLayerTreeNode* node, mChildren )
252  childrenDump << node->dump().split( "\n" );
253  for ( int i = 0; i < childrenDump.count(); ++i )
254  childrenDump[i].prepend( " " );
255  return header + childrenDump.join( "\n" );
256 }
257 
259 {
260  return new QgsLayerTreeGroup( *this );
261 }
262 
263 void QgsLayerTreeGroup::setVisible( Qt::CheckState state )
264 {
265  if ( mChecked == state )
266  return;
267 
268  mChecked = state;
269  emit visibilityChanged( this, state );
270 
271  if ( mChecked == Qt::Unchecked || mChecked == Qt::Checked )
272  {
273  mChangingChildVisibility = true; // guard against running again setVisible() triggered from children
274 
275  // update children to have the correct visibility
276  foreach ( QgsLayerTreeNode* child, mChildren )
277  {
278  if ( QgsLayerTree::isGroup( child ) )
280  else if ( QgsLayerTree::isLayer( child ) )
282  }
283 
284  mChangingChildVisibility = false;
285  }
286 }
287 
289 {
290  QStringList lst;
291  foreach ( QgsLayerTreeNode* child, mChildren )
292  {
293  if ( QgsLayerTree::isGroup( child ) )
294  lst << QgsLayerTree::toGroup( child )->findLayerIds();
295  else if ( QgsLayerTree::isLayer( child ) )
296  lst << QgsLayerTree::toLayer( child )->layerId();
297  }
298  return lst;
299 }
300 
301 
303 {
304  //QgsMapLayer* layer = static_cast<QgsMapLayer*>( sender() );
305  //removeLayer( layer );
306 }
307 
309 {
310  if ( mChildren.indexOf( node ) != -1 )
312 }
313 
315 {
317  return;
318 
319  if ( mChildren.count() == 0 )
320  return;
321 
322  bool hasVisible = false, hasHidden = false;
323 
324  foreach ( QgsLayerTreeNode* child, mChildren )
325  {
326  if ( QgsLayerTree::isLayer( child ) )
327  {
328  bool layerVisible = QgsLayerTree::toLayer( child )->isVisible() == Qt::Checked;
329  if ( layerVisible ) hasVisible = true;
330  if ( !layerVisible ) hasHidden = true;
331  }
332  else if ( QgsLayerTree::isGroup( child ) )
333  {
334  Qt::CheckState state = QgsLayerTree::toGroup( child )->isVisible();
335  if ( state == Qt::Checked || state == Qt::PartiallyChecked ) hasVisible = true;
336  if ( state == Qt::Unchecked || state == Qt::PartiallyChecked ) hasHidden = true;
337  }
338  }
339 
340  Qt::CheckState newState;
341  if ( hasVisible && !hasHidden )
342  newState = Qt::Checked;
343  else if ( hasHidden && !hasVisible )
344  newState = Qt::Unchecked;
345  else
346  newState = Qt::PartiallyChecked;
347 
348  setVisible( newState );
349 }
350 
void nodeVisibilityChanged(QgsLayerTreeNode *node)
Layer tree group node serves as a container for layers and further groups.
void removeChildren(int from, int count)
Remove child nodes from index "from". The nodes will be deleted.
static unsigned index
void removeChildrenGroupWithoutLayers()
Remove all child group nodes without layers. The groupnodes will be deleted.
Base class for all map layer types.
Definition: qgsmaplayer.h:48
static Qt::CheckState checkStateFromXml(QString txt)
Convert QString to Qt::CheckState.
QgsLayerTreeGroup * addGroup(const QString &name)
Append a new group node with given name. Newly created node is owned by this group.
void readChildrenFromXML(QDomElement &element)
Read children from XML and append them to the group.
static QString checkStateToXml(Qt::CheckState state)
Convert Qt::CheckState to QString.
virtual QString dump() const
Return text representation of the tree. For debugging purposes only.
static QgsLayerTreeGroup * readXML(QDomElement &element)
Read group (tree) from XML element and return the newly created group (or null on ...
QgsMapLayer * layer() const
void removeAllChildren()
Remove all child nodes. The nodes will be deleted.
bool mExpanded
whether the node should be shown in GUI as expanded
NodeType nodeType()
Find out about type of the node. It is usually shorter to use convenience functions from QgsLayerTree...
virtual QString dump() const =0
Return string with layer tree structure. For debug purposes only.
void removeChildNode(QgsLayerTreeNode *node)
Remove a child node from this group. The node will be deleted.
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.
virtual void writeXML(QDomElement &parentElement)=0
Write layer tree to XML.
void removeLayer(QgsMapLayer *layer)
Remove map layer's node from this group. The node will be deleted.
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
QgsLayerTreeLayer * addLayer(QgsMapLayer *layer)
Append a new layer node for given map layer. Newly created node is owned by this group.
void removeChildrenPrivate(int from, int count)
Low-level removal of children from the node.
Qt::CheckState isVisible() const
void visibilityChanged(QgsLayerTreeNode *node, Qt::CheckState state)
Emitted when check state of a node within the tree has been changed.
QgsLayerTreeLayer * insertLayer(int index, QgsMapLayer *layer)
Insert a new layer node for given map layer at specified position. Newly created node is owned by thi...
void insertChildrenPrivate(int index, QList< QgsLayerTreeNode * > nodes)
Low-level insertion of children to the node. The children must not have any parent yet! ...
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes. Searches recursively the whole sub-tree.
This class is a base class for nodes in a layer tree.
QString layerId() const
void setVisible(Qt::CheckState visible)
static QgsLayerTreeNode * readXML(QDomElement &element)
Read layer tree from XML. Returns new instance.
bool isExpanded() const
Return whether the node should be shown as expanded or collapsed in GUI.
QString name() const
Get group's name.
QList< QgsLayerTreeNode * > mChildren
list of children - node is responsible for their deletion
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
Qt::CheckState isVisible() const
Return the check state of the group node.
Qt::CheckState mChecked
virtual void writeXML(QDomElement &parentElement)
Write group (tree) as XML element and add it to the given parent element...
virtual QgsLayerTreeNode * clone() const
Return a clone of the group. The children are cloned too.
void writeCommonXML(QDomElement &element)
void insertChildNode(int index, QgsLayerTreeNode *node)
Insert existing node at specified position. The node must not have a parent yet. The node will be own...
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
QStringList findLayerIds() const
Find layer IDs used in all layer nodes. Searches recursively the whole sub-tree.
QgsLayerTreeGroup * findGroup(const QString &name)
Find group node with specified name. Searches recursively the whole sub-tree.
void addChildNode(QgsLayerTreeNode *node)
Append an existing node. The node must not have a parent yet. The node will be owned by this group...
QgsLayerTreeLayer * findLayer(const QString &layerId) const
Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tr...
container of other groups and layers
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
QgsLayerTreeGroup * insertGroup(int index, const QString &name)
Insert a new group node with given name at specified position. Newly created node is owned by this gr...
Layer tree node points to a map layer.
QgsLayerTreeGroup(const QString &name=QString(), Qt::CheckState checked=Qt::Checked)