QGIS API Documentation 3.99.0-Master (8e76e220402)
Loading...
Searching...
No Matches
qgslayertree.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayertree
3 ---------------------
4 begin : 22.3.2017
5 copyright : (C) 2017 by Matthias Kuhn
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 "qgslayertree.h"
17
19#include "qgsvectorlayer.h"
20
21#include <QString>
22
23#include "moc_qgslayertree.cpp"
24
25using namespace Qt::StringLiterals;
26
28{
29 init();
30}
31
33 : QgsLayerTreeGroup( other )
34 , mCustomLayerOrder( other.mCustomLayerOrder )
35 , mHasCustomLayerOrder( other.mHasCustomLayerOrder )
36{
37 init();
38}
39
40void QgsLayerTree::init()
41{
42 connect( this, &QgsLayerTree::addedChildren, this, &QgsLayerTree::nodeAddedChildren );
43 connect( this, &QgsLayerTree::removedChildren, this, &QgsLayerTree::nodeRemovedChildren );
44}
45
46QList<QgsMapLayer *> QgsLayerTree::customLayerOrder() const
47{
48 return _qgis_listQPointerToRaw( mCustomLayerOrder );
49}
50
51void QgsLayerTree::setCustomLayerOrder( const QList<QgsMapLayer *> &customLayerOrder )
52{
53 QgsWeakMapLayerPointerList newOrder = _qgis_listRawToQPointer( customLayerOrder );
54
55 if ( newOrder == mCustomLayerOrder )
56 return;
57
58 mCustomLayerOrder = newOrder;
60
61 if ( mHasCustomLayerOrder )
62 emit layerOrderChanged();
63}
64
66{
67 QList<QgsMapLayer *> layers;
68
69 for ( const auto &layerId : customLayerOrder )
70 {
71 QgsLayerTreeLayer *nodeLayer = findLayer( layerId );
72 if ( nodeLayer )
73 {
74 // configuration from 2.x projects might have non spatial layers
75 QgsMapLayer *layer = nodeLayer->layer();
76 if ( !layer || !layer->isSpatial() )
77 {
78 continue;
79 }
80 layers.append( layer );
81 }
82 }
83 setCustomLayerOrder( layers );
84}
85
86QList<QgsMapLayer *> QgsLayerTree::layerOrder() const
87{
88 if ( mHasCustomLayerOrder )
89 {
90 return customLayerOrder();
91 }
92 else
93 {
95 }
96}
97
99{
100 return mHasCustomLayerOrder;
101}
102
104{
105 if ( hasCustomLayerOrder == mHasCustomLayerOrder )
106 return;
107
108 mHasCustomLayerOrder = hasCustomLayerOrder;
109
111 emit layerOrderChanged();
112}
113
114QList< QgsLayerTreeNode * > QgsLayerTree::layerAndCustomNodeOrder() const
115{
117}
118
119std::unique_ptr< QgsLayerTree > QgsLayerTree::readXml( const QDomElement &element, const QgsReadWriteContext &context ) // cppcheck-suppress duplInheritedMember
120{
121 auto tree = std::make_unique< QgsLayerTree >();
122
123 tree->readCommonXml( element );
124
125 tree->readChildrenFromXml( element, context );
126
127 return tree;
128}
129
130void QgsLayerTree::writeXml( QDomElement &parentElement, const QgsReadWriteContext &context )
131{
132 QDomDocument doc = parentElement.ownerDocument();
133 QDomElement elem = doc.createElement( u"layer-tree-group"_s );
134
135 writeCommonXml( elem );
136
137 for ( QgsLayerTreeNode *node : std::as_const( mChildren ) )
138 node->writeXml( elem, context );
139
140 QDomElement customOrderElem = doc.createElement( u"custom-order"_s );
141 customOrderElem.setAttribute( u"enabled"_s, mHasCustomLayerOrder ? 1 : 0 );
142 elem.appendChild( customOrderElem );
143
144 for ( QgsMapLayer *layer : std::as_const( mCustomLayerOrder ) )
145 {
146 // Safety belt, see https://github.com/qgis/QGIS/issues/26975
147 // Crash when deleting an item from the layout legend
148 if ( ! layer )
149 continue;
150 QDomElement layerElem = doc.createElement( u"item"_s );
151 layerElem.appendChild( doc.createTextNode( layer->id() ) );
152 customOrderElem.appendChild( layerElem );
153 }
154
155 elem.appendChild( customOrderElem );
156
157 parentElement.appendChild( elem );
158}
159
161{
162 return new QgsLayerTree( *this );
163}
164
166{
168 setHasCustomLayerOrder( false );
169 setCustomLayerOrder( QStringList() );
170}
171
172void QgsLayerTree::nodeAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
173{
174 Q_ASSERT( node );
175
176 // collect layer IDs that have been added in order to put them into custom layer order
177 QList<QgsMapLayer *> layers;
178
179 QList<QgsLayerTreeNode *> children = node->children();
180 for ( int i = indexFrom; i <= indexTo; ++i )
181 {
182 QgsLayerTreeNode *child = children.at( i );
183 if ( QgsLayerTree::isLayer( child ) )
184 {
185 layers << QgsLayerTree::toLayer( child )->layer();
186 }
187 else if ( QgsLayerTree::isGroup( child ) )
188 {
189 const auto nodeLayers = QgsLayerTree::toGroup( child )->findLayers();
190 for ( QgsLayerTreeLayer *nodeL : nodeLayers )
191 layers << nodeL->layer();
192 }
193 }
194
195 for ( QgsMapLayer *layer : std::as_const( layers ) )
196 {
197 if ( !mCustomLayerOrder.contains( layer ) && layer )
198 mCustomLayerOrder.append( layer );
199 }
200
202 emit layerOrderChanged();
203}
204
205void QgsLayerTree::nodeRemovedChildren()
206{
207 QList<QgsMapLayer *> layers = customLayerOrder();
208 auto layer = layers.begin();
209
210 while ( layer != layers.end() )
211 {
212 if ( !findLayer( *layer ) )
213 layer = layers.erase( layer );
214 else
215 ++layer;
216 }
217
218 // we need to ensure that the customLayerOrderChanged signal is ALWAYS raised
219 // here, since that order HAS changed due to removal of the child!
220 // setCustomLayerOrder will only emit this signal when the layers list
221 // at this stage is different to the stored customer layer order. If this
222 // isn't the case (i.e. the lists ARE the same) then manually emit the
223 // signal
224 const bool emitSignal = _qgis_listRawToQPointer( layers ) == mCustomLayerOrder;
225
226 setCustomLayerOrder( layers );
227 if ( emitSignal )
229
230 emit layerOrderChanged();
231}
232
233void QgsLayerTree::addMissingLayers()
234{
235 bool changed = false;
236
237 const QList< QgsLayerTreeLayer * > layers = findLayers();
238 for ( const auto layer : layers )
239 {
240 if ( !mCustomLayerOrder.contains( layer->layer() ) &&
241 layer->layer() && layer->layer()->isSpatial() )
242 {
243 mCustomLayerOrder.append( layer->layer() );
244 changed = true;
245 }
246 }
247
248 if ( changed )
249 {
251 if ( mHasCustomLayerOrder )
252 emit layerOrderChanged();
253 }
254}
255
256void QgsLayerTree::readLayerOrderFromXml( const QDomElement &elem )
257{
258 QStringList order;
259
260 QDomElement customOrderElem = elem.firstChildElement( u"custom-order"_s );
261 if ( !customOrderElem.isNull() )
262 {
263 setHasCustomLayerOrder( customOrderElem.attribute( u"enabled"_s ).toInt() );
264
265 QDomElement itemElem = customOrderElem.firstChildElement( u"item"_s );
266 while ( !itemElem.isNull() )
267 {
268 order.append( itemElem.text() );
269 itemElem = itemElem.nextSiblingElement( u"item"_s );
270 }
271 }
272
273 setCustomLayerOrder( order );
274 addMissingLayers();
275}
Layer tree group node serves as a container for layers and further groups.
QList< QgsMapLayer * > layerOrderRespectingGroupLayers() const
Returns an ordered list of map layers in the group, ignoring any layers which are child layers of Qgs...
QList< QgsLayerTreeNode * > layerAndCustomNodeOrderRespectingGroupLayers() const
Returns an ordered list of map layers and custom nodes in the group, ignoring any layers which are ch...
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.
Layer tree node points to a map layer.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
Base class for nodes in a layer tree.
void removedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Emitted when one or more nodes has been removed from a node within the tree.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
QgsLayerTreeNode(NodeType t, bool checked=true)
Constructor.
void writeCommonXml(QDomElement &element)
Write common XML elements.
void addedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Emitted when one or more nodes have been added to a node within the tree.
QList< QgsLayerTreeNode * > mChildren
list of children - node is responsible for their deletion
Namespace with helper functions for layer tree operations.
bool hasCustomLayerOrder() const
Determines if the layer order should be derived from the layer tree or if a custom override order sha...
void customLayerOrderChanged()
Emitted when the custom layer order has changed.
void readLayerOrderFromXml(const QDomElement &doc)
Load the layer order from an XML element.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
void writeXml(QDomElement &parentElement, const QgsReadWriteContext &context) override
Write layer tree to XML.
QList< QgsMapLayer * > layerOrder() const
The order in which layers will be rendered on the canvas.
QgsLayerTree()
Create a new empty layer tree.
static std::unique_ptr< QgsLayerTree > readXml(const QDomElement &element, const QgsReadWriteContext &context)
Load the layer tree from an XML element.
void hasCustomLayerOrderChanged(bool hasCustomLayerOrder)
Emitted when the hasCustomLayerOrder flag changes.
void clear()
Clear any information from this layer tree.
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
void setHasCustomLayerOrder(bool hasCustomLayerOrder)
Determines if the layer order should be derived from the layer tree or if a custom override order sha...
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
void setCustomLayerOrder(const QList< QgsMapLayer * > &customLayerOrder)
The order in which layers will be rendered on the canvas.
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
void layerOrderChanged()
Emitted when the layer order has changed.
QList< QgsMapLayer * > customLayerOrder() const
The order in which layers will be rendered on the canvas.
QList< QgsLayerTreeNode * > layerAndCustomNodeOrder() const
The order in which layers and custom nodes will be rendered on the canvas.
QgsLayerTree * clone() const override
Create a copy of the node. Returns new instance.
Base class for all map layer types.
Definition qgsmaplayer.h:83
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
A container for the context for various read/write operations on objects.
QList< QgsWeakMapLayerPointer > QgsWeakMapLayerPointerList
A list of weak pointers to QgsMapLayers.