QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgslayertreeutils.cpp
Go to the documentation of this file.
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#include <QTextStream>
24
25static void _readOldLegendGroup( const QDomElement &groupElem, QgsLayerTreeGroup *parent );
26static void _readOldLegendLayer( const QDomElement &layerElem, QgsLayerTreeGroup *parent );
27
28bool QgsLayerTreeUtils::readOldLegend( QgsLayerTreeGroup *root, const QDomElement &legendElem )
29{
30 if ( legendElem.isNull() )
31 return false;
32
33 const QDomNodeList legendChildren = legendElem.childNodes();
34
35 for ( int i = 0; i < legendChildren.size(); ++i )
36 {
37 const 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
53static bool _readOldLegendLayerOrderGroup( const QDomElement &groupElem, QMap<int, QString> &layerIndexes )
54{
55 const QDomNodeList legendChildren = groupElem.childNodes();
56
57 for ( int i = 0; i < legendChildren.size(); ++i )
58 {
59 const QDomElement currentChildElem = legendChildren.at( i ).toElement();
60 if ( currentChildElem.tagName() == QLatin1String( "legendlayer" ) )
61 {
62 const QDomElement layerFileElem = currentChildElem.firstChildElement( QStringLiteral( "filegroup" ) ).firstChildElement( QStringLiteral( "legendlayerfile" ) );
63
64 const 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
80bool 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 const 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 QgsDebugMsgLevel( layerId, 2 );
100 order.append( layerId );
101 }
102
103 return true;
104}
105
106
107static 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() ? QStringLiteral( "true" ) : QStringLiteral( "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
135static void _writeOldLegendGroupChildren( QDomDocument &doc, QDomElement &groupElem, QgsLayerTreeGroup *nodeGroup, bool hasCustomOrder, const QList<QgsMapLayer *> &order );
136
137static 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() ? QStringLiteral( "true" ) : QStringLiteral( "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
155static 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
172QDomElement 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
183QString 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 return QStringLiteral( "Qt::Checked" );
193 }
194 return QString();
195}
196
197Qt::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
209static void _readOldLegendGroup( const QDomElement &groupElem, QgsLayerTreeGroup *parent )
210{
211 const 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 const 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
240static void _readOldLegendLayer( const QDomElement &layerElem, QgsLayerTreeGroup *parent )
241{
242 const QDomElement layerFileElem = layerElem.firstChildElement( QStringLiteral( "filegroup" ) ).firstChildElement( QStringLiteral( "legendlayerfile" ) );
243 const 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
263bool QgsLayerTreeUtils::layersEditable( const QList<QgsLayerTreeLayer *> &layerNodes, bool ignoreLayersWhichCannotBeToggled )
264{
265 const auto constLayerNodes = layerNodes;
266 for ( QgsLayerTreeLayer *layerNode : constLayerNodes )
267 {
268 QgsMapLayer *layer = layerNode->layer();
269 if ( !layer )
270 continue;
271
272 if ( layer->isEditable() && ( !ignoreLayersWhichCannotBeToggled || !( layer->properties() & Qgis::MapLayerProperty::UsersCannotToggleEditing ) ) )
273 return true;
274 }
275 return false;
276}
277
278bool QgsLayerTreeUtils::layersModified( const QList<QgsLayerTreeLayer *> &layerNodes )
279{
280 const auto constLayerNodes = layerNodes;
281 for ( QgsLayerTreeLayer *layerNode : constLayerNodes )
282 {
283 QgsMapLayer *layer = layerNode->layer();
284 if ( !layer )
285 continue;
286
287 if ( layer->isEditable() && layer->isModified() )
288 return true;
289 }
290 return false;
291}
292
294{
295 QList<QgsLayerTreeNode *> nodesToRemove;
296 const auto constChildren = group->children();
297 for ( QgsLayerTreeNode *node : constChildren )
298 {
299 if ( QgsLayerTree::isGroup( node ) )
301 else if ( QgsLayerTree::isLayer( node ) )
302 {
303 if ( !QgsLayerTree::toLayer( node )->layer() )
304 nodesToRemove << node;
305 }
306 }
307
308 const auto constNodesToRemove = nodesToRemove;
309 for ( QgsLayerTreeNode *node : constNodesToRemove )
310 group->removeChildNode( node );
311}
312
314{
315 const QDomElement projectLayersElement { doc->documentElement().firstChildElement( QStringLiteral( "projectlayers" ) ) };
316
317 std::function<void ( QgsLayerTreeNode * )> _store = [ & ]( QgsLayerTreeNode * node )
318 {
319 if ( QgsLayerTree::isLayer( node ) )
320 {
321 if ( QgsMapLayer *l = QgsLayerTree::toLayer( node )->layer() )
322 {
323 // no need to store for annotation layers, they can never break!
324 if ( l->type() == Qgis::LayerType::Annotation )
325 return;
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 const QList<QgsLayerTreeNode *> children = group->children();
354 for ( QgsLayerTreeNode *node : children )
355 {
356 _store( node );
357 }
358}
359
361{
362 QStringList list;
363
364 if ( QgsLayerTree::isGroup( node ) )
365 {
366 const auto constChildren = QgsLayerTree::toGroup( node )->children();
367 for ( QgsLayerTreeNode *child : constChildren )
368 {
369 if ( child->itemVisibilityChecked() == Qt::Unchecked )
370 {
371 list << invisibleLayerList( child );
372 }
373 }
374 }
375 else if ( QgsLayerTree::isLayer( node ) )
376 {
378
379 if ( !layer->isVisible() )
380 list << layer->layerId();
381 }
382
383 return list;
384}
385
387{
388 const auto constChildren = group->children();
389 for ( QgsLayerTreeNode *child : constChildren )
390 {
391 if ( QgsLayerTree::isGroup( child ) )
392 {
393 if ( child->customProperty( QStringLiteral( "embedded" ) ).toInt() )
394 {
395 child->setCustomProperty( QStringLiteral( "embedded-invisible-layers" ), invisibleLayerList( child ) );
397 }
398 else
399 {
401 }
402 }
403 }
404}
405
406
408{
409 const auto constChildren = group->children();
410 for ( QgsLayerTreeNode *node : constChildren )
411 {
412 if ( !node->customProperty( QStringLiteral( "embedded_project" ) ).toString().isEmpty() )
413 {
414 // may change from absolute path to relative path
415 const QString newPath = project->writePath( node->customProperty( QStringLiteral( "embedded_project" ) ).toString() );
416 node->setCustomProperty( QStringLiteral( "embedded_project" ), newPath );
417 }
418
419 if ( QgsLayerTree::isGroup( node ) )
420 {
422 }
423 }
424}
425
426void QgsLayerTreeUtils::setLegendFilterByExpression( QgsLayerTreeLayer &layer, const QString &expr, bool enabled )
427{
428 layer.setCustomProperty( QStringLiteral( "legend/expressionFilter" ), expr );
429 layer.setCustomProperty( QStringLiteral( "legend/expressionFilterEnabled" ), enabled && !expr.isEmpty() );
430}
431
433{
434 const QString expression = layer.customProperty( QStringLiteral( "legend/expressionFilter" ), QString() ).toString();
435 if ( enabled )
436 *enabled = !expression.isEmpty() && layer.customProperty( QStringLiteral( "legend/expressionFilterEnabled" ), QString() ).toBool();
437 return expression;
438}
439
441{
442 const auto constFindLayers = group.findLayers();
443 for ( QgsLayerTreeLayer *l : constFindLayers )
444 {
445 bool exprEnabled;
446 const QString expr = legendFilterByExpression( *l, &exprEnabled );
447 if ( exprEnabled && !expr.isEmpty() )
448 {
449 return true;
450 }
451 }
452 return false;
453}
454
456{
457 // get the index of the reflayer
458 QgsLayerTreeLayer *inTree = group->findLayer( refLayer->id() );
459 if ( !inTree )
460 return nullptr;
461
462 int idx = 0;
463 const auto constChildren = inTree->parent()->children();
464 for ( QgsLayerTreeNode *vl : constChildren )
465 {
466 if ( vl->nodeType() == QgsLayerTreeNode::NodeLayer && static_cast<QgsLayerTreeLayer *>( vl )->layer() == refLayer )
467 {
468 break;
469 }
470 idx++;
471 }
472 // insert the new layer
473 QgsLayerTreeGroup *parent = static_cast<QgsLayerTreeGroup *>( inTree->parent() ) ? static_cast<QgsLayerTreeGroup *>( inTree->parent() ) : group;
474 return parent->insertLayer( idx + 1, layerToInsert );
475}
476
477static void _collectMapLayers( const QList<QgsLayerTreeNode *> &nodes, QSet<QgsMapLayer *> &layersSet )
478{
479 for ( QgsLayerTreeNode *node : nodes )
480 {
481 if ( QgsLayerTree::isLayer( node ) )
482 {
483 QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
484 if ( nodeLayer->layer() )
485 layersSet << nodeLayer->layer();
486 }
487 else if ( QgsLayerTree::isGroup( node ) )
488 {
489 _collectMapLayers( QgsLayerTree::toGroup( node )->children(), layersSet );
490 }
491 }
492}
493
494QSet<QgsMapLayer *> QgsLayerTreeUtils::collectMapLayersRecursive( const QList<QgsLayerTreeNode *> &nodes )
495{
496 QSet<QgsMapLayer *> layersSet;
497 _collectMapLayers( nodes, layersSet );
498 return layersSet;
499}
500
502{
503 if ( QgsLayerTree::isLayer( tree ) )
504 {
505 if ( QgsLayerTree::toLayer( tree )->layer() == layer )
506 return 1;
507 return 0;
508 }
509
510 int cnt = 0;
511 const QList<QgsLayerTreeNode *> children = tree->children();
512 for ( QgsLayerTreeNode *child : children )
513 cnt += countMapLayerInTree( child, layer );
514 return cnt;
515}
516
518{
519 // if the group is embedded go to the first non-embedded group, at worst the top level item
520 while ( group->customProperty( property ).toInt() )
521 {
522 if ( !group->parent() )
523 break;
524
525 if ( QgsLayerTree::isGroup( group->parent() ) )
526 group = QgsLayerTree::toGroup( group->parent() );
527 else
528 Q_ASSERT( false );
529 }
530 return group;
531}
532
534{
535 int vectorLineIndex = 0;
536 int vectorPolygonIndex = 0;
537 int pointCloudIndex = 0;
538 int meshIndex = 0;
539 int rasterIndex = 0;
540 int basemapIndex = 0;
541
542 const QList<QgsLayerTreeNode *> children = group->children();
543 int nodeIdx = 0;
544 for ( const QgsLayerTreeNode *child : children )
545 {
546 if ( QgsLayerTree::isLayer( child ) )
547 {
548 nodeIdx++;
549 const QgsMapLayer *layer = qobject_cast<const QgsLayerTreeLayer *>( child )->layer();
550 switch ( layer->type() )
551 {
553 {
554 const QgsVectorLayer *vlayer = static_cast<const QgsVectorLayer *>( layer );
555 if ( vlayer->geometryType() == Qgis::GeometryType::Point )
556 {
557 if ( vectorLineIndex < nodeIdx )
558 vectorLineIndex = nodeIdx;
559 if ( vectorPolygonIndex < nodeIdx )
560 vectorPolygonIndex = nodeIdx;
561 if ( pointCloudIndex < nodeIdx )
562 pointCloudIndex = nodeIdx;
563 if ( meshIndex < nodeIdx )
564 meshIndex = nodeIdx;
565 if ( rasterIndex < nodeIdx )
566 rasterIndex = nodeIdx;
567 if ( basemapIndex < nodeIdx )
568 basemapIndex = nodeIdx;
569 }
570 else if ( vlayer->geometryType() == Qgis::GeometryType::Line )
571 {
572 if ( vectorPolygonIndex < nodeIdx )
573 vectorPolygonIndex = nodeIdx;
574 if ( pointCloudIndex < nodeIdx )
575 pointCloudIndex = nodeIdx;
576 if ( meshIndex < nodeIdx )
577 meshIndex = nodeIdx;
578 if ( rasterIndex < nodeIdx )
579 rasterIndex = nodeIdx;
580 if ( basemapIndex < nodeIdx )
581 basemapIndex = nodeIdx;
582 }
583 else if ( vlayer->geometryType() == Qgis::GeometryType::Polygon )
584 {
585 if ( pointCloudIndex < nodeIdx )
586 pointCloudIndex = nodeIdx;
587 if ( meshIndex < nodeIdx )
588 meshIndex = nodeIdx;
589 if ( rasterIndex < nodeIdx )
590 rasterIndex = nodeIdx;
591 if ( basemapIndex < nodeIdx )
592 basemapIndex = nodeIdx;
593 }
594 break;
595 }
596
598 {
599 if ( meshIndex < nodeIdx )
600 meshIndex = nodeIdx;
601 if ( rasterIndex < nodeIdx )
602 rasterIndex = nodeIdx;
603 if ( basemapIndex < nodeIdx )
604 basemapIndex = nodeIdx;
605 break;
606 }
607
609 {
610 if ( rasterIndex < nodeIdx )
611 rasterIndex = nodeIdx;
612 if ( basemapIndex < nodeIdx )
613 basemapIndex = nodeIdx;
614 break;
615 }
616
618 {
619 if ( layer->dataProvider() && layer->dataProvider()->name() == QLatin1String( "gdal" ) )
620 {
621 // Assume non-gdal raster layers are most likely to be base maps (e.g. XYZ raster)
622 // Admittedly a gross assumption, but better than nothing
623 if ( basemapIndex < nodeIdx )
624 basemapIndex = nodeIdx;
625 }
626 break;
627 }
628
633 default:
634 break;
635 }
636 }
637 }
638
639 int index = 0;
640 switch ( layer->type() )
641 {
643 {
644 QgsVectorLayer *vlayer = static_cast<QgsVectorLayer *>( layer );
645 if ( vlayer->geometryType() == Qgis::GeometryType::Point )
646 {
647 index = 0;
648 }
649 else if ( vlayer->geometryType() == Qgis::GeometryType::Line )
650 {
651 index = vectorLineIndex;
652 }
653 else if ( vlayer->geometryType() == Qgis::GeometryType::Polygon )
654 {
655 index = vectorPolygonIndex;
656 }
657 break;
658 }
659
661 {
662 index = pointCloudIndex;
663 break;
664 }
665
667 {
668 index = meshIndex;
669 break;
670 }
671
673 {
674 if ( layer->dataProvider() && layer->dataProvider()->name() == QLatin1String( "gdal" ) )
675 {
676 index = rasterIndex;
677 }
678 else
679 {
680 index = basemapIndex;
681 }
682 break;
683 }
684
686 {
687 index = basemapIndex;
688 break;
689 }
690
694 default:
695 break;
696 }
697 return group->insertLayer( index, layer );
698}
@ UsersCannotToggleEditing
Indicates that users are not allowed to toggle editing for this layer. Note that this does not imply ...
@ Polygon
Polygons.
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ Vector
Vector layer.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ Raster
Raster layer.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
virtual QString name() const =0
Returns a provider name.
Layer tree group node serves as a container for layers and further groups.
void removeChildNode(QgsLayerTreeNode *node)
Remove a child node from this group.
QString name() const override
Returns the group's name.
void addChildNode(QgsLayerTreeNode *node)
Append an existing node.
void removeAllChildren()
Remove all child nodes.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
QgsLayerTreeLayer * insertLayer(int index, QgsMapLayer *layer)
Insert a new layer node for given map layer at specified position.
Layer tree node points to a map layer.
QString layerId() const
Returns the ID for the map layer associated with this node.
QString name() const override
Returns the layer's name.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
This class is a base class for nodes in a layer tree.
@ NodeLayer
Leaf node pointing to a layer.
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.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
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 * parent()
Gets pointer to the parent. If parent is nullptr, the node is a root node.
bool isExpanded() const
Returns whether the node should be shown as expanded or collapsed in GUI.
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
bool itemVisibilityChecked() const
Returns whether a node is checked (independently of its ancestors or children)
static bool layersEditable(const QList< QgsLayerTreeLayer * > &layerNodes, bool ignoreLayersWhichCannotBeToggled=false)
Returns true if any of the specified layers is editable.
static QString checkStateToXml(Qt::CheckState state)
Convert Qt::CheckState to QString.
static void replaceChildrenOfEmbeddedGroups(QgsLayerTreeGroup *group)
Remove subtree of embedded groups and replaces it with a custom property embedded-visible-layers.
static QgsLayerTreeLayer * insertLayerBelow(QgsLayerTreeGroup *group, const QgsMapLayer *refLayer, QgsMapLayer *layerToInsert)
Insert a QgsMapLayer just below another one.
static void setLegendFilterByExpression(QgsLayerTreeLayer &layer, const QString &expr, bool enabled=true)
Sets the expression filter of a legend layer.
static QString legendFilterByExpression(const QgsLayerTreeLayer &layer, bool *enabled=nullptr)
Returns the expression filter of a legend layer.
static void storeOriginalLayersProperties(QgsLayerTreeGroup *group, const QDomDocument *doc)
Stores in a layer's originalXmlProperties the layer properties information.
static QSet< QgsMapLayer * > collectMapLayersRecursive(const QList< QgsLayerTreeNode * > &nodes)
Returns map layers from the given list of layer tree nodes.
static bool hasLegendFilterExpression(const QgsLayerTreeGroup &group)
Test if one of the layers in a group has an expression filter.
static int countMapLayerInTree(QgsLayerTreeNode *tree, QgsMapLayer *layer)
Returns how many occurrences of a map layer are there in a layer tree.
static QDomElement writeOldLegend(QDomDocument &doc, QgsLayerTreeGroup *root, bool hasCustomOrder, const QList< QgsMapLayer * > &order)
Returns.
static bool readOldLegendLayerOrder(const QDomElement &legendElem, bool &hasCustomOrder, QStringList &order)
Try to load custom layer order from.
static QgsLayerTreeLayer * insertLayerAtOptimalPlacement(QgsLayerTreeGroup *group, QgsMapLayer *layer)
Inserts a layer within a given group at an optimal index position by insuring a given layer type will...
static void updateEmbeddedGroupsProjectPath(QgsLayerTreeGroup *group, const QgsProject *project)
Updates an embedded group from a project.
static bool readOldLegend(QgsLayerTreeGroup *root, const QDomElement &legendElem)
Try to load layer tree from.
static QgsLayerTreeGroup * firstGroupWithoutCustomProperty(QgsLayerTreeGroup *group, const QString &property)
Returns the first parent which doesn't have the given custom property or the group itself if it doesn...
static void removeInvalidLayers(QgsLayerTreeGroup *group)
Removes layer nodes that refer to invalid layers.
static Qt::CheckState checkStateFromXml(const QString &txt)
Convert QString to Qt::CheckState.
static QStringList invisibleLayerList(QgsLayerTreeNode *node)
Gets invisible layers.
static bool layersModified(const QList< QgsLayerTreeLayer * > &layerNodes)
Returns true if any of the layers is modified.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:70
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:50
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:41
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:60
Base class for all map layer types.
Definition: qgsmaplayer.h:75
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Qgis::LayerType type
Definition: qgsmaplayer.h:82
virtual Qgis::MapLayerProperties properties() const
Returns the map layer properties of this layer.
virtual bool isEditable() const
Returns true if the layer can be edited.
virtual bool isModified() const
Returns true if the layer has been modified since last commit/save.
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:107
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
#define str(x)
Definition: qgis.cpp:38
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39