1 /***************************************************************************
2 qgslayertreeutils.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 "qgslayertreeutils.h"
17 #include "qgslayertree.h"
18 #include "qgsvectorlayer.h"
19 #include "qgsproject.h"
20 #include "qgslogger.h"
21
22 #include <QDomElement>
23
24
25 static void _readOldLegendGroup( const QDomElement &groupElem, QgsLayerTreeGroup *parent );
26 static void _readOldLegendLayer( const QDomElement &layerElem, QgsLayerTreeGroup *parent );
27
readOldLegend(QgsLayerTreeGroup * root,const QDomElement & legendElem)28 bool QgsLayerTreeUtils::readOldLegend( QgsLayerTreeGroup *root, const QDomElement &legendElem )
29 {
30 if ( legendElem.isNull() )
31 return false;
32
33 QDomNodeList legendChildren = legendElem.childNodes();
34
35 for ( int i = 0; i < legendChildren.size(); ++i )
36 {
37 QDomElement currentChildElem = legendChildren.at( i ).toElement();
38 if ( currentChildElem.tagName() == QLatin1String( "legendlayer" ) )
39 {
40 _readOldLegendLayer( currentChildElem, root );
41 }
42 else if ( currentChildElem.tagName() == QLatin1String( "legendgroup" ) )
43 {
44 _readOldLegendGroup( currentChildElem, root );
45 }
46 }
47
48 return true;
49 }
50
51
52
_readOldLegendLayerOrderGroup(const QDomElement & groupElem,QMap<int,QString> & layerIndexes)53 static bool _readOldLegendLayerOrderGroup( const QDomElement &groupElem, QMap<int, QString> &layerIndexes )
54 {
55 QDomNodeList legendChildren = groupElem.childNodes();
56
57 for ( int i = 0; i < legendChildren.size(); ++i )
58 {
59 QDomElement currentChildElem = legendChildren.at( i ).toElement();
60 if ( currentChildElem.tagName() == QLatin1String( "legendlayer" ) )
61 {
62 QDomElement layerFileElem = currentChildElem.firstChildElement( QStringLiteral( "filegroup" ) ).firstChildElement( QStringLiteral( "legendlayerfile" ) );
63
64 int layerIndex = currentChildElem.attribute( QStringLiteral( "drawingOrder" ) ).toInt();
65 if ( layerIndex == -1 )
66 return false; // order undefined
67 layerIndexes.insert( layerIndex, layerFileElem.attribute( QStringLiteral( "layerid" ) ) );
68 }
69 else if ( currentChildElem.tagName() == QLatin1String( "legendgroup" ) )
70 {
71 if ( !_readOldLegendLayerOrderGroup( currentChildElem, layerIndexes ) )
72 return false;
73 }
74 }
75
76 return true;
77 }
78
79
readOldLegendLayerOrder(const QDomElement & legendElem,bool & hasCustomOrder,QStringList & order)80 bool QgsLayerTreeUtils::readOldLegendLayerOrder( const QDomElement &legendElem, bool &hasCustomOrder, QStringList &order )
81 {
82 if ( legendElem.isNull() )
83 return false;
84
85 hasCustomOrder = legendElem.attribute( QStringLiteral( "updateDrawingOrder" ) ) == QLatin1String( "false" );
86 order.clear();
87
88 QMap<int, QString> layerIndexes;
89
90 // try to read the order. may be undefined (order = -1) for some or all items
91 bool res = _readOldLegendLayerOrderGroup( legendElem, layerIndexes );
92
93 if ( !res && hasCustomOrder )
94 return false; // invalid state
95
96 const auto constLayerIndexes = layerIndexes;
97 for ( const QString &layerId : constLayerIndexes )
98 {
99 QgsDebugMsg( layerId );
100 order.append( layerId );
101 }
102
103 return true;
104 }
105
106
_writeOldLegendLayer(QDomDocument & doc,QgsLayerTreeLayer * nodeLayer,bool hasCustomOrder,const QList<QgsMapLayer * > & order)107 static QDomElement _writeOldLegendLayer( QDomDocument &doc, QgsLayerTreeLayer *nodeLayer, bool hasCustomOrder, const QList<QgsMapLayer *> &order )
108 {
109 int drawingOrder = -1;
110 if ( hasCustomOrder )
111 drawingOrder = order.indexOf( nodeLayer->layer() );
112
113 QDomElement layerElem = doc.createElement( QStringLiteral( "legendlayer" ) );
114 layerElem.setAttribute( QStringLiteral( "drawingOrder" ), drawingOrder );
115 layerElem.setAttribute( QStringLiteral( "open" ), nodeLayer->isExpanded() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
116 layerElem.setAttribute( QStringLiteral( "checked" ), QgsLayerTreeUtils::checkStateToXml( nodeLayer->itemVisibilityChecked() ? Qt::Checked : Qt::Unchecked ) );
117 layerElem.setAttribute( QStringLiteral( "name" ), nodeLayer->name() );
118 layerElem.setAttribute( QStringLiteral( "showFeatureCount" ), nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ) ).toInt() );
119
120 QDomElement fileGroupElem = doc.createElement( QStringLiteral( "filegroup" ) );
121 fileGroupElem.setAttribute( QStringLiteral( "open" ), nodeLayer->isExpanded() ? "true" : "false" );
122 fileGroupElem.setAttribute( QStringLiteral( "hidden" ), QStringLiteral( "false" ) );
123
124 QDomElement layerFileElem = doc.createElement( QStringLiteral( "legendlayerfile" ) );
125 layerFileElem.setAttribute( QStringLiteral( "isInOverview" ), nodeLayer->customProperty( QStringLiteral( "overview" ) ).toInt() );
126 layerFileElem.setAttribute( QStringLiteral( "layerid" ), nodeLayer->layerId() );
127 layerFileElem.setAttribute( QStringLiteral( "visible" ), nodeLayer->isVisible() ? 1 : 0 );
128
129 layerElem.appendChild( fileGroupElem );
130 fileGroupElem.appendChild( layerFileElem );
131 return layerElem;
132 }
133
134 // need forward declaration as write[..]Group and write[..]GroupChildren call each other
135 static void _writeOldLegendGroupChildren( QDomDocument &doc, QDomElement &groupElem, QgsLayerTreeGroup *nodeGroup, bool hasCustomOrder, const QList<QgsMapLayer *> &order );
136
_writeOldLegendGroup(QDomDocument & doc,QgsLayerTreeGroup * nodeGroup,bool hasCustomOrder,const QList<QgsMapLayer * > & order)137 static QDomElement _writeOldLegendGroup( QDomDocument &doc, QgsLayerTreeGroup *nodeGroup, bool hasCustomOrder, const QList<QgsMapLayer *> &order )
138 {
139 QDomElement groupElem = doc.createElement( QStringLiteral( "legendgroup" ) );
140 groupElem.setAttribute( QStringLiteral( "open" ), nodeGroup->isExpanded() ? "true" : "false" );
141 groupElem.setAttribute( QStringLiteral( "name" ), nodeGroup->name() );
142 groupElem.setAttribute( QStringLiteral( "checked" ), QgsLayerTreeUtils::checkStateToXml( nodeGroup->itemVisibilityChecked() ? Qt::Checked : Qt::Unchecked ) );
143
144 if ( nodeGroup->customProperty( QStringLiteral( "embedded" ) ).toInt() )
145 {
146 groupElem.setAttribute( QStringLiteral( "embedded" ), 1 );
147 groupElem.setAttribute( QStringLiteral( "project" ), nodeGroup->customProperty( QStringLiteral( "embedded_project" ) ).toString() );
148 }
149
150 _writeOldLegendGroupChildren( doc, groupElem, nodeGroup, hasCustomOrder, order );
151 return groupElem;
152 }
153
154
_writeOldLegendGroupChildren(QDomDocument & doc,QDomElement & groupElem,QgsLayerTreeGroup * nodeGroup,bool hasCustomOrder,const QList<QgsMapLayer * > & order)155 static void _writeOldLegendGroupChildren( QDomDocument &doc, QDomElement &groupElem, QgsLayerTreeGroup *nodeGroup, bool hasCustomOrder, const QList<QgsMapLayer *> &order )
156 {
157 const auto constChildren = nodeGroup->children();
158 for ( QgsLayerTreeNode *node : constChildren )
159 {
160 if ( QgsLayerTree::isGroup( node ) )
161 {
162 groupElem.appendChild( _writeOldLegendGroup( doc, QgsLayerTree::toGroup( node ), hasCustomOrder, order ) );
163 }
164 else if ( QgsLayerTree::isLayer( node ) )
165 {
166 groupElem.appendChild( _writeOldLegendLayer( doc, QgsLayerTree::toLayer( node ), hasCustomOrder, order ) );
167 }
168 }
169 }
170
171
writeOldLegend(QDomDocument & doc,QgsLayerTreeGroup * root,bool hasCustomOrder,const QList<QgsMapLayer * > & order)172 QDomElement QgsLayerTreeUtils::writeOldLegend( QDomDocument &doc, QgsLayerTreeGroup *root, bool hasCustomOrder, const QList<QgsMapLayer *> &order )
173 {
174 QDomElement legendElem = doc.createElement( QStringLiteral( "legend" ) );
175 legendElem.setAttribute( QStringLiteral( "updateDrawingOrder" ), hasCustomOrder ? QStringLiteral( "false" ) : QStringLiteral( "true" ) );
176
177 _writeOldLegendGroupChildren( doc, legendElem, root, hasCustomOrder, order );
178
179 return legendElem;
180 }
181
182
checkStateToXml(Qt::CheckState state)183 QString QgsLayerTreeUtils::checkStateToXml( Qt::CheckState state )
184 {
185 switch ( state )
186 {
187 case Qt::Unchecked:
188 return QStringLiteral( "Qt::Unchecked" );
189 case Qt::PartiallyChecked:
190 return QStringLiteral( "Qt::PartiallyChecked" );
191 case Qt::Checked:
192 default:
193 return QStringLiteral( "Qt::Checked" );
194 }
195 }
196
checkStateFromXml(const QString & txt)197 Qt::CheckState QgsLayerTreeUtils::checkStateFromXml( const QString &txt )
198 {
199 if ( txt == QLatin1String( "Qt::Unchecked" ) )
200 return Qt::Unchecked;
201 else if ( txt == QLatin1String( "Qt::PartiallyChecked" ) )
202 return Qt::PartiallyChecked;
203 else // "Qt::Checked"
204 return Qt::Checked;
205 }
206
207
208
_readOldLegendGroup(const QDomElement & groupElem,QgsLayerTreeGroup * parent)209 static void _readOldLegendGroup( const QDomElement &groupElem, QgsLayerTreeGroup *parent )
210 {
211 QDomNodeList groupChildren = groupElem.childNodes();
212
213 QgsLayerTreeGroup *groupNode = new QgsLayerTreeGroup( groupElem.attribute( QStringLiteral( "name" ) ) );
214
215 groupNode->setItemVisibilityChecked( QgsLayerTreeUtils::checkStateFromXml( groupElem.attribute( QStringLiteral( "checked" ) ) ) != Qt::Unchecked );
216 groupNode->setExpanded( groupElem.attribute( QStringLiteral( "open" ) ) == QLatin1String( "true" ) );
217
218 if ( groupElem.attribute( QStringLiteral( "embedded" ) ) == QLatin1String( "1" ) )
219 {
220 groupNode->setCustomProperty( QStringLiteral( "embedded" ), 1 );
221 groupNode->setCustomProperty( QStringLiteral( "embedded_project" ), groupElem.attribute( QStringLiteral( "project" ) ) );
222 }
223
224 for ( int i = 0; i < groupChildren.size(); ++i )
225 {
226 QDomElement currentChildElem = groupChildren.at( i ).toElement();
227 if ( currentChildElem.tagName() == QLatin1String( "legendlayer" ) )
228 {
229 _readOldLegendLayer( currentChildElem, groupNode );
230 }
231 else if ( currentChildElem.tagName() == QLatin1String( "legendgroup" ) )
232 {
233 _readOldLegendGroup( currentChildElem, groupNode );
234 }
235 }
236
237 parent->addChildNode( groupNode );
238 }
239
_readOldLegendLayer(const QDomElement & layerElem,QgsLayerTreeGroup * parent)240 static void _readOldLegendLayer( const QDomElement &layerElem, QgsLayerTreeGroup *parent )
241 {
242 QDomElement layerFileElem = layerElem.firstChildElement( QStringLiteral( "filegroup" ) ).firstChildElement( QStringLiteral( "legendlayerfile" ) );
243 QString layerId = layerFileElem.attribute( QStringLiteral( "layerid" ) );
244 QgsLayerTreeLayer *layerNode = new QgsLayerTreeLayer( layerId, layerElem.attribute( QStringLiteral( "name" ) ) );
245
246 layerNode->setItemVisibilityChecked( QgsLayerTreeUtils::checkStateFromXml( layerElem.attribute( QStringLiteral( "checked" ) ) ) != Qt::Unchecked );
247 layerNode->setExpanded( layerElem.attribute( QStringLiteral( "open" ) ) == QLatin1String( "true" ) );
248
249 if ( layerFileElem.attribute( QStringLiteral( "isInOverview" ) ) == QLatin1String( "1" ) )
250 layerNode->setCustomProperty( QStringLiteral( "overview" ), 1 );
251
252 if ( layerElem.attribute( QStringLiteral( "embedded" ) ) == QLatin1String( "1" ) )
253 layerNode->setCustomProperty( QStringLiteral( "embedded" ), 1 );
254
255 if ( layerElem.attribute( QStringLiteral( "showFeatureCount" ) ) == QLatin1String( "1" ) )
256 layerNode->setCustomProperty( QStringLiteral( "showFeatureCount" ), 1 );
257
258 // drawing order is handled by readOldLegendLayerOrder()
259
260 parent->addChildNode( layerNode );
261 }
262
263
264
layersEditable(const QList<QgsLayerTreeLayer * > & layerNodes)265 bool QgsLayerTreeUtils::layersEditable( const QList<QgsLayerTreeLayer *> &layerNodes )
266 {
267 const auto constLayerNodes = layerNodes;
268 for ( QgsLayerTreeLayer *layerNode : constLayerNodes )
269 {
270 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerNode->layer() );
271 if ( !vl )
272 continue;
273
274 if ( vl->isEditable() )
275 return true;
276 }
277 return false;
278 }
279
layersModified(const QList<QgsLayerTreeLayer * > & layerNodes)280 bool QgsLayerTreeUtils::layersModified( const QList<QgsLayerTreeLayer *> &layerNodes )
281 {
282 const auto constLayerNodes = layerNodes;
283 for ( QgsLayerTreeLayer *layerNode : constLayerNodes )
284 {
285 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerNode->layer() );
286 if ( !vl )
287 continue;
288
289 if ( vl->isEditable() && vl->isModified() )
290 return true;
291 }
292 return false;
293 }
294
removeInvalidLayers(QgsLayerTreeGroup * group)295 void QgsLayerTreeUtils::removeInvalidLayers( QgsLayerTreeGroup *group )
296 {
297 QList<QgsLayerTreeNode *> nodesToRemove;
298 const auto constChildren = group->children();
299 for ( QgsLayerTreeNode *node : constChildren )
300 {
301 if ( QgsLayerTree::isGroup( node ) )
302 removeInvalidLayers( QgsLayerTree::toGroup( node ) );
303 else if ( QgsLayerTree::isLayer( node ) )
304 {
305 if ( !QgsLayerTree::toLayer( node )->layer() )
306 nodesToRemove << node;
307 }
308 }
309
310 const auto constNodesToRemove = nodesToRemove;
311 for ( QgsLayerTreeNode *node : constNodesToRemove )
312 group->removeChildNode( node );
313 }
314
storeOriginalLayersProperties(QgsLayerTreeGroup * group,const QDomDocument * doc)315 void QgsLayerTreeUtils::storeOriginalLayersProperties( QgsLayerTreeGroup *group, const QDomDocument *doc )
316 {
317
318 const QDomElement projectLayersElement { doc->documentElement().firstChildElement( QStringLiteral( "projectlayers" ) ) };
319
320 std::function<void ( QgsLayerTreeNode * )> _store = [ & ]( QgsLayerTreeNode * node )
321 {
322 if ( QgsLayerTree::isLayer( node ) )
323 {
324 QgsMapLayer *l( QgsLayerTree::toLayer( node )->layer() );
325 if ( l )
326 {
327 QDomElement layerElement { projectLayersElement.firstChildElement( QStringLiteral( "maplayer" ) ) };
328 while ( ! layerElement.isNull() )
329 {
330 const QString id( layerElement.firstChildElement( QStringLiteral( "id" ) ).firstChild().nodeValue() );
331 if ( id == l->id() )
332 {
333 QString str;
334 QTextStream stream( &str );
335 layerElement.save( stream, 4 /*indent*/ );
336 l->setOriginalXmlProperties( QStringLiteral( "<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>\n%1" ).arg( str ) );
337 break;
338 }
339 layerElement = layerElement.nextSiblingElement( );
340 }
341 }
342 }
343 else if ( QgsLayerTree::isGroup( node ) )
344 {
345 const QList<QgsLayerTreeNode *> constChildren( node->children( ) );
346 for ( const auto &childNode : constChildren )
347 {
348 _store( childNode );
349 }
350 }
351 };
352
353 for ( QgsLayerTreeNode *node : group->children() )
354 {
355 _store( node );
356 }
357 }
358
invisibleLayerList(QgsLayerTreeNode * node)359 QStringList QgsLayerTreeUtils::invisibleLayerList( QgsLayerTreeNode *node )
360 {
361 QStringList list;
362
363 if ( QgsLayerTree::isGroup( node ) )
364 {
365 const auto constChildren = QgsLayerTree::toGroup( node )->children();
366 for ( QgsLayerTreeNode *child : constChildren )
367 {
368 if ( child->itemVisibilityChecked() == Qt::Unchecked )
369 {
370 list << invisibleLayerList( child );
371 }
372 }
373 }
374 else if ( QgsLayerTree::isLayer( node ) )
375 {
376 QgsLayerTreeLayer *layer = QgsLayerTree::toLayer( node );
377
378 if ( !layer->isVisible() )
379 list << layer->layerId();
380 }
381
382 return list;
383 }
384
replaceChildrenOfEmbeddedGroups(QgsLayerTreeGroup * group)385 void QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTreeGroup *group )
386 {
387 const auto constChildren = group->children();
388 for ( QgsLayerTreeNode *child : constChildren )
389 {
390 if ( QgsLayerTree::isGroup( child ) )
391 {
392 if ( child->customProperty( QStringLiteral( "embedded" ) ).toInt() )
393 {
394 child->setCustomProperty( QStringLiteral( "embedded-invisible-layers" ), invisibleLayerList( child ) );
395 QgsLayerTree::toGroup( child )->removeAllChildren();
396 }
397 else
398 {
399 replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( child ) );
400 }
401 }
402 }
403 }
404
405
updateEmbeddedGroupsProjectPath(QgsLayerTreeGroup * group,const QgsProject * project)406 void QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTreeGroup *group, const QgsProject *project )
407 {
408 const auto constChildren = group->children();
409 for ( QgsLayerTreeNode *node : constChildren )
410 {
411 if ( !node->customProperty( QStringLiteral( "embedded_project" ) ).toString().isEmpty() )
412 {
413 // may change from absolute path to relative path
414 QString newPath = project->writePath( node->customProperty( QStringLiteral( "embedded_project" ) ).toString() );
415 node->setCustomProperty( QStringLiteral( "embedded_project" ), newPath );
416 }
417
418 if ( QgsLayerTree::isGroup( node ) )
419 {
420 updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( node ), project );
421 }
422 }
423 }
424
setLegendFilterByExpression(QgsLayerTreeLayer & layer,const QString & expr,bool enabled)425 void QgsLayerTreeUtils::setLegendFilterByExpression( QgsLayerTreeLayer &layer, const QString &expr, bool enabled )
426 {
427 layer.setCustomProperty( QStringLiteral( "legend/expressionFilter" ), expr );
428 layer.setCustomProperty( QStringLiteral( "legend/expressionFilterEnabled" ), enabled && !expr.isEmpty() );
429 }
430
legendFilterByExpression(const QgsLayerTreeLayer & layer,bool * enabled)431 QString QgsLayerTreeUtils::legendFilterByExpression( const QgsLayerTreeLayer &layer, bool *enabled )
432 {
433 const QString expression = layer.customProperty( QStringLiteral( "legend/expressionFilter" ), QString() ).toString();
434 if ( enabled )
435 *enabled = !expression.isEmpty() && layer.customProperty( QStringLiteral( "legend/expressionFilterEnabled" ), QString() ).toBool();
436 return expression;
437 }
438
hasLegendFilterExpression(const QgsLayerTreeGroup & group)439 bool QgsLayerTreeUtils::hasLegendFilterExpression( const QgsLayerTreeGroup &group )
440 {
441 const auto constFindLayers = group.findLayers();
442 for ( QgsLayerTreeLayer *l : constFindLayers )
443 {
444 bool exprEnabled;
445 QString expr = legendFilterByExpression( *l, &exprEnabled );
446 if ( exprEnabled && !expr.isEmpty() )
447 {
448 return true;
449 }
450 }
451 return false;
452 }
453
insertLayerBelow(QgsLayerTreeGroup * group,const QgsMapLayer * refLayer,QgsMapLayer * layerToInsert)454 QgsLayerTreeLayer *QgsLayerTreeUtils::insertLayerBelow( QgsLayerTreeGroup *group, const QgsMapLayer *refLayer, QgsMapLayer *layerToInsert )
455 {
456 // get the index of the reflayer
457 QgsLayerTreeLayer *inTree = group->findLayer( refLayer->id() );
458 if ( !inTree )
459 return nullptr;
460
461 int idx = 0;
462 const auto constChildren = inTree->parent()->children();
463 for ( QgsLayerTreeNode *vl : constChildren )
464 {
465 if ( vl->nodeType() == QgsLayerTreeNode::NodeLayer && static_cast<QgsLayerTreeLayer *>( vl )->layer() == refLayer )
466 {
467 break;
468 }
469 idx++;
470 }
471 // insert the new layer
472 QgsLayerTreeGroup *parent = static_cast<QgsLayerTreeGroup *>( inTree->parent() ) ? static_cast<QgsLayerTreeGroup *>( inTree->parent() ) : group;
473 return parent->insertLayer( idx, layerToInsert );
474 }
475
_collectMapLayers(const QList<QgsLayerTreeNode * > & nodes,QSet<QgsMapLayer * > & layersSet)476 static void _collectMapLayers( const QList<QgsLayerTreeNode *> &nodes, QSet<QgsMapLayer *> &layersSet )
477 {
478 for ( QgsLayerTreeNode *node : nodes )
479 {
480 if ( QgsLayerTree::isLayer( node ) )
481 {
482 QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
483 if ( nodeLayer->layer() )
484 layersSet << nodeLayer->layer();
485 }
486 else if ( QgsLayerTree::isGroup( node ) )
487 {
488 _collectMapLayers( QgsLayerTree::toGroup( node )->children(), layersSet );
489 }
490 }
491 }
492
collectMapLayersRecursive(const QList<QgsLayerTreeNode * > & nodes)493 QSet<QgsMapLayer *> QgsLayerTreeUtils::collectMapLayersRecursive( const QList<QgsLayerTreeNode *> &nodes )
494 {
495 QSet<QgsMapLayer *> layersSet;
496 _collectMapLayers( nodes, layersSet );
497 return layersSet;
498 }
499
countMapLayerInTree(QgsLayerTreeNode * tree,QgsMapLayer * layer)500 int QgsLayerTreeUtils::countMapLayerInTree( QgsLayerTreeNode *tree, QgsMapLayer *layer )
501 {
502 if ( QgsLayerTree::isLayer( tree ) )
503 {
504 if ( QgsLayerTree::toLayer( tree )->layer() == layer )
505 return 1;
506 return 0;
507 }
508
509 int cnt = 0;
510 const QList<QgsLayerTreeNode *> children = tree->children();
511 for ( QgsLayerTreeNode *child : children )
512 cnt += countMapLayerInTree( child, layer );
513 return cnt;
514 }
515
firstGroupWithoutCustomProperty(QgsLayerTreeGroup * group,const QString & property)516 QgsLayerTreeGroup *QgsLayerTreeUtils::firstGroupWithoutCustomProperty( QgsLayerTreeGroup *group, const QString &property )
517 {
518 // if the group is embedded go to the first non-embedded group, at worst the top level item
519 while ( group->customProperty( property ).toInt() )
520 {
521 if ( !group->parent() )
522 break;
523
524 if ( QgsLayerTree::isGroup( group->parent() ) )
525 group = QgsLayerTree::toGroup( group->parent() );
526 else
527 Q_ASSERT( false );
528 }
529 return group;
530 }
531