QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
qgslayertreenode.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayertreenode.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 "qgslayertreenode.h"
17 
18 #include "qgslayertree.h"
19 #include "qgslayertreeutils.h"
20 
21 #include <QDomElement>
22 #include <QStringList>
23 
24 
26  : mNodeType( t )
27  , mChecked( checked )
28  , mExpanded( true )
29 {
30 }
31 
33  : QObject( nullptr )
34  , mNodeType( other.mNodeType )
35  , mChecked( other.mChecked )
36  , mExpanded( other.mExpanded )
37  , mProperties( other.mProperties )
38 {
39  QList<QgsLayerTreeNode *> clonedChildren;
40 
41  for ( QgsLayerTreeNode *child : std::as_const( other.mChildren ) )
42  clonedChildren << child->clone();
43  insertChildrenPrivate( -1, clonedChildren );
44 }
45 
47 {
48  qDeleteAll( mChildren );
49 }
50 
51 QList<QgsLayerTreeNode *> QgsLayerTreeNode::abandonChildren()
52 {
53  const QList<QgsLayerTreeNode *> orphans { mChildren };
54  mChildren.clear();
55  for ( auto orphan : std::as_const( orphans ) )
56  {
57  orphan->makeOrphan( );
58  }
59  return orphans;
60 }
61 
63 {
64  disconnect();
65  mParent = nullptr;
66 }
67 
68 QgsLayerTreeNode *QgsLayerTreeNode::readXml( QDomElement &element, const QgsReadWriteContext &context )
69 {
70  QgsLayerTreeNode *node = nullptr;
71  if ( element.tagName() == QLatin1String( "layer-tree-group" ) )
72  node = QgsLayerTreeGroup::readXml( element, context );
73  else if ( element.tagName() == QLatin1String( "layer-tree-layer" ) )
74  node = QgsLayerTreeLayer::readXml( element, context );
75 
76  return node;
77 }
78 
79 QgsLayerTreeNode *QgsLayerTreeNode::readXml( QDomElement &element, const QgsProject *project )
80 {
81  QgsReadWriteContext context;
82  QgsPathResolver resolver;
83  if ( project )
84  resolver = project->pathResolver();
85  context.setPathResolver( resolver );
86  context.setProjectTranslator( const_cast<QgsProject *>( project ) );
87 
88  QgsLayerTreeNode *node = readXml( element, context );
89  if ( node )
90  node->resolveReferences( project );
91  return node;
92 }
93 
94 
96 {
97  if ( mChecked == checked )
98  return;
99  mChecked = checked;
100  emit visibilityChanged( this );
101 }
102 
104 {
105  setItemVisibilityChecked( checked );
106 }
107 
109 {
110  setItemVisibilityChecked( checked );
111  if ( mParent )
113 }
114 
116 {
117  return mChecked && ( !mParent || mParent->isVisible() );
118 }
119 
120 
122 {
123  return mExpanded;
124 }
125 
127 {
128  if ( !mChecked )
129  return false;
130  const auto constMChildren = mChildren;
131  for ( QgsLayerTreeNode *child : constMChildren )
132  {
133  if ( !child->isItemVisibilityCheckedRecursive() )
134  return false;
135  }
136 
137  return true;
138 }
139 
141 {
142  if ( mChecked )
143  return false;
144  const auto constMChildren = mChildren;
145  for ( QgsLayerTreeNode *child : constMChildren )
146  {
147  if ( !child->isItemVisibilityUncheckedRecursive() )
148  return false;
149  }
150 
151  return true;
152 }
153 
154 void fetchCheckedLayers( const QgsLayerTreeNode *node, QList<QgsMapLayer *> &layers )
155 {
156  if ( QgsLayerTree::isLayer( node ) )
157  {
158  const QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
159  if ( nodeLayer->isVisible() )
160  layers << nodeLayer->layer();
161  }
162 
163  const auto constChildren = node->children();
164  for ( QgsLayerTreeNode *child : constChildren )
165  {
166  if ( QgsLayerTreeGroup *group = qobject_cast< QgsLayerTreeGroup * >( child ) )
167  {
168  if ( QgsGroupLayer *groupLayer = group->groupLayer() )
169  {
170  layers << groupLayer;
171  continue;
172  }
173  }
174 
175  fetchCheckedLayers( child, layers );
176  }
177 }
178 
179 QList<QgsMapLayer *> QgsLayerTreeNode::checkedLayers() const
180 {
181  QList<QgsMapLayer *> layers;
182  fetchCheckedLayers( this, layers );
183  return layers;
184 }
185 
187 {
188  int depth = 0;
189  QgsLayerTreeNode *node = mParent;
190  while ( node )
191  {
192  node = node->parent();
193  ++depth;
194  }
195  return depth;
196 }
197 
198 void QgsLayerTreeNode::setExpanded( bool expanded )
199 {
200  if ( mExpanded == expanded )
201  return;
202 
203  mExpanded = expanded;
204  emit expandedChanged( this, expanded );
205 }
206 
207 
208 void QgsLayerTreeNode::setCustomProperty( const QString &key, const QVariant &value )
209 {
210  if ( !mProperties.contains( key ) || mProperties.value( key ) != value )
211  {
212  mProperties.setValue( key, value );
213  emit customPropertyChanged( this, key );
214  }
215 }
216 
217 QVariant QgsLayerTreeNode::customProperty( const QString &key, const QVariant &defaultValue ) const
218 {
219  return mProperties.value( key, defaultValue );
220 }
221 
222 void QgsLayerTreeNode::removeCustomProperty( const QString &key )
223 {
224  if ( mProperties.contains( key ) )
225  {
226  mProperties.remove( key );
227  emit customPropertyChanged( this, key );
228  }
229 }
230 
232 {
233  return mProperties.keys();
234 }
235 
236 void QgsLayerTreeNode::readCommonXml( QDomElement &element )
237 {
238  mProperties.readXml( element );
239 }
240 
241 void QgsLayerTreeNode::writeCommonXml( QDomElement &element )
242 {
243  QDomDocument doc( element.ownerDocument() );
244  mProperties.writeXml( element, doc );
245 }
246 
247 void QgsLayerTreeNode::insertChildrenPrivate( int index, const QList<QgsLayerTreeNode *> &nodes )
248 {
249  if ( nodes.isEmpty() )
250  return;
251 
252  for ( QgsLayerTreeNode *node : nodes )
253  {
254  Q_ASSERT( !node->mParent );
255  node->mParent = this;
256  }
257 
258  if ( index < 0 || index >= mChildren.count() )
259  index = mChildren.count();
260 
261  for ( int i = 0; i < nodes.count(); ++i )
262  {
263  QgsLayerTreeNode *node = nodes.at( i );
264 
265  const QList<QgsLayerTreeNode *> orphans { node->abandonChildren() };
266 
267  emit willAddChildren( this, index + i, index + i );
268  mChildren.insert( index + i, node );
269  emit addedChildren( this, index + i, index + i );
270 
271  // forward the signal towards the root
280 
281  // Now add children
282  if ( ! orphans.isEmpty() )
283  {
284  node->insertChildrenPrivate( -1, orphans );
285  }
286 
287  // ensure initial expanded state for node is respected
288  emit expandedChanged( node, node->isExpanded() );
289  }
290 }
291 
292 void QgsLayerTreeNode::removeChildrenPrivate( int from, int count, bool destroy )
293 {
294  if ( from < 0 || count <= 0 )
295  return;
296 
297  const int to = from + count - 1;
298  if ( to >= mChildren.count() )
299  return;
300 
301  // Remove in reverse order
302  while ( --count >= 0 )
303  {
304  const int last { from + count };
305  Q_ASSERT( last >= 0 && last < mChildren.count( ) );
306  QgsLayerTreeNode *node = mChildren.at( last );
307 
308  // Remove children first
309  if ( ! node->children().isEmpty() )
310  {
311  node->removeChildrenPrivate( 0, node->children().count( ), destroy );
312  }
313 
314  emit willRemoveChildren( this, last, last );
315  node = mChildren.takeAt( last );
316  if ( destroy )
317  {
318  delete node;
319  }
320  else
321  {
322  node->makeOrphan();
323  }
324  emit removedChildren( this, last, last );
325  }
326 }
327 
329 {
330  int index = mChildren.indexOf( node );
331  if ( index < 0 )
332  return false;
333 
334  int n = mChildren.size();
335 
336  removeChildrenPrivate( index, 1, false );
337 
338  return mChildren.size() < n;
339 }
A map layer which consists of a set of child layers, where all component layers are rendered as a sin...
Definition: qgsgrouplayer.h:42
Layer tree group node serves as a container for layers and further groups.
static QgsLayerTreeGroup * readXml(QDomElement &element, const QgsReadWriteContext &context)
Read group (tree) from XML element <layer-tree-group> and return the newly created group (or nullptr ...
Layer tree node points to a map layer.
static QgsLayerTreeLayer * readXml(QDomElement &element, const QgsReadWriteContext &context)
Read layer node from XML.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
This class is a base class for nodes in a layer tree.
void readCommonXml(QDomElement &element)
Read common XML elements.
QList< QgsLayerTreeNode * > abandonChildren()
Removes the children, disconnect all the forwarded and external signals and sets their parent to null...
virtual void makeOrphan()
Sets parent to nullptr and disconnects all external and forwarded signals.
NodeType
Enumeration of possible tree node types.
void removedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Emitted when one or more nodes has been removed from a node within the tree.
void nameChanged(QgsLayerTreeNode *node, QString name)
Emitted when the name of the node is changed.
bool isVisible() const
Returns whether a node is really visible (ie checked and all its ancestors checked as well)
void setCustomProperty(const QString &key, const QVariant &value)
Sets a custom property for the node. Properties are stored in a map and saved in project file.
bool isItemVisibilityUncheckedRecursive() const
Returns whether this node is unchecked and all its children.
static QgsLayerTreeNode * readXml(QDomElement &element, const QgsReadWriteContext &context)
Read layer tree from XML.
void willRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Emitted when one or more nodes will be removed from a node within the tree.
void removeCustomProperty(const QString &key)
Remove a custom property from layer. Properties are stored in a map and saved in project file.
~QgsLayerTreeNode() override
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file.
void setExpanded(bool expanded)
Sets whether the node should be shown as expanded or collapsed in GUI.
QgsLayerTreeNode(NodeType t, bool checked=true)
Constructor.
void writeCommonXml(QDomElement &element)
Write common XML elements.
QgsObjectCustomProperties mProperties
custom properties attached to the node
void customPropertyChanged(QgsLayerTreeNode *node, const QString &key)
Emitted when a custom property of a node within the tree has been changed or removed.
QgsLayerTreeNode * parent()
Gets pointer to the parent. If parent is nullptr, the node is a root node.
void insertChildrenPrivate(int index, const QList< QgsLayerTreeNode * > &nodes)
Low-level insertion of children to the node. The children must not have any parent yet!
int depth() const
Returns the depth of this node, i.e.
void addedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Emitted when one or more nodes have been added to a node within the tree.
bool takeChild(QgsLayerTreeNode *node)
Remove a child from a node.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
void willAddChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Emitted when one or more nodes will be added to a node within the tree.
void visibilityChanged(QgsLayerTreeNode *node)
Emitted when check state of a node within the tree has been changed.
QList< QgsLayerTreeNode * > mChildren
list of children - node is responsible for their deletion
virtual void setItemVisibilityCheckedRecursive(bool checked)
Check or uncheck a node and all its children (taking into account exclusion rules)
bool mExpanded
whether the node should be shown in GUI as expanded
bool isExpanded() const
Returns whether the node should be shown as expanded or collapsed in GUI.
QStringList customProperties() const
Returns list of keys stored in custom properties.
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
QList< QgsMapLayer * > checkedLayers() const
Returns a list of any checked layers which belong to this node or its children.
QgsLayerTreeNode * mParent
pointer to the parent node - nullptr in case of root node
bool isItemVisibilityCheckedRecursive() const
Returns whether this node is checked and all its children.
virtual void resolveReferences(const QgsProject *project, bool looseMatching=false)=0
Turn textual references to layers into map layer object from project.
void expandedChanged(QgsLayerTreeNode *node, bool expanded)
Emitted when the collapsed/expanded state of a node within the tree has been changed.
void removeChildrenPrivate(int from, int count, bool destroy=true)
Low-level removal of children from the node.
void setItemVisibilityCheckedParentRecursive(bool checked)
Check or uncheck a node and all its parents.
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:50
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:70
void setValue(const QString &key, const QVariant &value)
Add an entry to the store with the specified key.
QStringList keys() const
Returns a list of all stored keys.
void writeXml(QDomNode &parentNode, QDomDocument &doc) const
Writes the store contents to an XML node.
void remove(const QString &key)
Removes a key (entry) from the store.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Returns the value for the given key.
void readXml(const QDomNode &parentNode, const QString &keyStartsWith=QString())
Read store contents from an XML node.
bool contains(const QString &key) const
Returns true if the properties contains a key with the specified name.
Resolves relative paths into absolute paths and vice versa.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:107
QgsPathResolver pathResolver() const
Returns path resolver object with considering whether the project uses absolute or relative paths and...
The class is used as a container of context for various read/write operations on other objects.
void setProjectTranslator(QgsProjectTranslator *projectTranslator)
Sets the project translator.
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
void fetchCheckedLayers(const QgsLayerTreeNode *node, QList< QgsMapLayer * > &layers)