QGIS API Documentation  2.9.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 #include "qgsmaplayer.h"
21 #include "qgsmaplayerregistry.h"
22 
23 #include <QDomElement>
24 #include <QStringList>
25 
26 
27 QgsLayerTreeGroup::QgsLayerTreeGroup( const QString& name, Qt::CheckState checked )
28  : QgsLayerTreeNode( NodeGroup )
29  , mName( name )
30  , mChecked( checked )
31  , mChangingChildVisibility( false )
32 {
33  connect( this, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
34 }
35 
37  : QgsLayerTreeNode( other )
38  , mName( other.mName )
39  , mChecked( other.mChecked )
40  , mChangingChildVisibility( false )
41 {
42  connect( this, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
43 }
44 
45 
47 {
48  QgsLayerTreeGroup* grp = new QgsLayerTreeGroup( name );
49  insertChildNode( index, grp );
50  return grp;
51 }
52 
54 {
55  QgsLayerTreeGroup* grp = new QgsLayerTreeGroup( name );
56  addChildNode( grp );
57  return grp;
58 }
59 
61 {
62  if ( !layer || QgsMapLayerRegistry::instance()->mapLayer( layer->id() ) != layer )
63  return 0;
64 
65  QgsLayerTreeLayer* ll = new QgsLayerTreeLayer( layer );
66  insertChildNode( index, ll );
67  return ll;
68 }
69 
71 {
72  if ( !layer || QgsMapLayerRegistry::instance()->mapLayer( layer->id() ) != layer )
73  return 0;
74 
75  QgsLayerTreeLayer* ll = new QgsLayerTreeLayer( layer );
76  addChildNode( ll );
77  return ll;
78 }
79 
81 {
82  QList<QgsLayerTreeNode*> nodes;
83  nodes << node;
84  insertChildNodes( index, nodes );
85 }
86 
87 void QgsLayerTreeGroup::insertChildNodes( int index, QList<QgsLayerTreeNode*> nodes )
88 {
89  // low-level insert
90  insertChildrenPrivate( index, nodes );
91 
93 }
94 
96 {
97  insertChildNode( -1, node );
98 }
99 
101 {
102  int i = mChildren.indexOf( node );
103  if ( i >= 0 )
104  removeChildren( i, 1 );
105 }
106 
108 {
109  foreach ( QgsLayerTreeNode* child, mChildren )
110  {
111  if ( QgsLayerTree::isLayer( child ) )
112  {
113  QgsLayerTreeLayer* childLayer = QgsLayerTree::toLayer( child );
114  if ( childLayer->layer() == layer )
115  {
116  removeChildren( mChildren.indexOf( child ), 1 );
117  break;
118  }
119  }
120  }
121 }
122 
123 void QgsLayerTreeGroup::removeChildren( int from, int count )
124 {
125  removeChildrenPrivate( from, count );
126 
128 }
129 
131 {
132  // clean the layer tree by removing empty group
133  foreach ( QgsLayerTreeNode* treeNode, children() )
134  {
135  if ( treeNode->nodeType() == QgsLayerTreeNode::NodeGroup )
136  {
137  QgsLayerTreeGroup* treeGroup = qobject_cast<QgsLayerTreeGroup*>( treeNode );
138  if ( treeGroup->findLayerIds().count() == 0 )
139  removeChildNode( treeNode );
140  else
142  }
143  }
144 }
145 
147 {
148  removeChildren( 0, mChildren.count() );
149 }
150 
151 QgsLayerTreeLayer *QgsLayerTreeGroup::findLayer( const QString& layerId ) const
152 {
153  foreach ( QgsLayerTreeNode* child, mChildren )
154  {
155  if ( QgsLayerTree::isLayer( child ) )
156  {
157  QgsLayerTreeLayer* childLayer = QgsLayerTree::toLayer( child );
158  if ( childLayer->layerId() == layerId )
159  return childLayer;
160  }
161  else if ( QgsLayerTree::isGroup( child ) )
162  {
163  QgsLayerTreeLayer* res = QgsLayerTree::toGroup( child )->findLayer( layerId );
164  if ( res )
165  return res;
166  }
167  }
168  return 0;
169 }
170 
171 QList<QgsLayerTreeLayer*> QgsLayerTreeGroup::findLayers() const
172 {
173  QList<QgsLayerTreeLayer*> list;
174  foreach ( QgsLayerTreeNode* child, mChildren )
175  {
176  if ( QgsLayerTree::isLayer( child ) )
177  list << QgsLayerTree::toLayer( child );
178  else if ( QgsLayerTree::isGroup( child ) )
179  list << QgsLayerTree::toGroup( child )->findLayers();
180  }
181  return list;
182 }
183 
185 {
186  foreach ( QgsLayerTreeNode* child, mChildren )
187  {
188  if ( QgsLayerTree::isGroup( child ) )
189  {
190  QgsLayerTreeGroup* childGroup = QgsLayerTree::toGroup( child );
191  if ( childGroup->name() == name )
192  return childGroup;
193  else
194  {
195  QgsLayerTreeGroup* grp = childGroup->findGroup( name );
196  if ( grp )
197  return grp;
198  }
199  }
200  }
201  return 0;
202 }
203 
205 {
206  if ( element.tagName() != "layer-tree-group" )
207  return 0;
208 
209  QString name = element.attribute( "name" );
210  bool isExpanded = ( element.attribute( "expanded", "1" ) == "1" );
211  Qt::CheckState checked = QgsLayerTreeUtils::checkStateFromXml( element.attribute( "checked" ) );
212 
213  QgsLayerTreeGroup* groupNode = new QgsLayerTreeGroup( name, checked );
214  groupNode->setExpanded( isExpanded );
215 
216  groupNode->readCommonXML( element );
217 
218  groupNode->readChildrenFromXML( element );
219 
220  return groupNode;
221 }
222 
223 void QgsLayerTreeGroup::writeXML( QDomElement& parentElement )
224 {
225  QDomDocument doc = parentElement.ownerDocument();
226  QDomElement elem = doc.createElement( "layer-tree-group" );
227  elem.setAttribute( "name", mName );
228  elem.setAttribute( "expanded", mExpanded ? "1" : "0" );
229  elem.setAttribute( "checked", QgsLayerTreeUtils::checkStateToXml( mChecked ) );
230 
231  writeCommonXML( elem );
232 
233  foreach ( QgsLayerTreeNode* node, mChildren )
234  node->writeXML( elem );
235 
236  parentElement.appendChild( elem );
237 }
238 
239 void QgsLayerTreeGroup::readChildrenFromXML( QDomElement& element )
240 {
241  QList<QgsLayerTreeNode*> nodes;
242  QDomElement childElem = element.firstChildElement();
243  while ( !childElem.isNull() )
244  {
245  QgsLayerTreeNode* newNode = QgsLayerTreeNode::readXML( childElem );
246  if ( newNode )
247  nodes << newNode;
248 
249  childElem = childElem.nextSiblingElement();
250  }
251 
252  insertChildNodes( -1, nodes );
253 }
254 
255 QString QgsLayerTreeGroup::dump() const
256 {
257  QString header = QString( "GROUP: %1 visible=%2 expanded=%3\n" ).arg( name() ).arg( mChecked ).arg( mExpanded );
258  QStringList childrenDump;
259  foreach ( QgsLayerTreeNode* node, mChildren )
260  childrenDump << node->dump().split( "\n" );
261  for ( int i = 0; i < childrenDump.count(); ++i )
262  childrenDump[i].prepend( " " );
263  return header + childrenDump.join( "\n" );
264 }
265 
267 {
268  return new QgsLayerTreeGroup( *this );
269 }
270 
271 void QgsLayerTreeGroup::setVisible( Qt::CheckState state )
272 {
273  if ( mChecked == state )
274  return;
275 
276  mChecked = state;
277  emit visibilityChanged( this, state );
278 
279  if ( mChecked == Qt::Unchecked || mChecked == Qt::Checked )
280  {
281  mChangingChildVisibility = true; // guard against running again setVisible() triggered from children
282 
283  // update children to have the correct visibility
284  foreach ( QgsLayerTreeNode* child, mChildren )
285  {
286  if ( QgsLayerTree::isGroup( child ) )
288  else if ( QgsLayerTree::isLayer( child ) )
290  }
291 
292  mChangingChildVisibility = false;
293  }
294 }
295 
297 {
298  QStringList lst;
299  foreach ( QgsLayerTreeNode* child, mChildren )
300  {
301  if ( QgsLayerTree::isGroup( child ) )
302  lst << QgsLayerTree::toGroup( child )->findLayerIds();
303  else if ( QgsLayerTree::isLayer( child ) )
304  lst << QgsLayerTree::toLayer( child )->layerId();
305  }
306  return lst;
307 }
308 
309 
311 {
312  //QgsMapLayer* layer = static_cast<QgsMapLayer*>( sender() );
313  //removeLayer( layer );
314 }
315 
317 {
318  if ( mChildren.indexOf( node ) != -1 )
320 }
321 
323 {
325  return;
326 
327  if ( mChildren.count() == 0 )
328  return;
329 
330  bool hasVisible = false, hasHidden = false;
331 
332  foreach ( QgsLayerTreeNode* child, mChildren )
333  {
334  if ( QgsLayerTree::isLayer( child ) )
335  {
336  bool layerVisible = QgsLayerTree::toLayer( child )->isVisible() == Qt::Checked;
337  if ( layerVisible ) hasVisible = true;
338  if ( !layerVisible ) hasHidden = true;
339  }
340  else if ( QgsLayerTree::isGroup( child ) )
341  {
342  Qt::CheckState state = QgsLayerTree::toGroup( child )->isVisible();
343  if ( state == Qt::Checked || state == Qt::PartiallyChecked ) hasVisible = true;
344  if ( state == Qt::Unchecked || state == Qt::PartiallyChecked ) hasHidden = true;
345  }
346  }
347 
348  Qt::CheckState newState;
349  if ( hasVisible && !hasHidden )
350  newState = Qt::Checked;
351  else if ( hasHidden && !hasVisible )
352  newState = Qt::Unchecked;
353  else
354  newState = Qt::PartiallyChecked;
355 
356  setVisible( newState );
357 }
358 
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:49
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.
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
static QgsMapLayerRegistry * instance()
Definition: qgssingleton.h:23
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.
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 id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:98
QString layerId() const
void setVisible(Qt::CheckState visible)
virtual QgsLayerTreeNode * clone() const override
Return a clone of the group. The children are cloned too.
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) override
Write group (tree) as XML element and add it to the given parent element...
void removeChildrenPrivate(int from, int count, bool destroy=true)
Low-level removal of children from the node.
virtual QString dump() const override
Return text representation of the tree. For debugging purposes only.
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)