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