QGIS API Documentation 3.99.0-Master (26c88405ac0)
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 "moc_qgslayertree.cpp"
22
24{
25 init();
26}
27
29 : QgsLayerTreeGroup( other )
30 , mCustomLayerOrder( other.mCustomLayerOrder )
31 , mHasCustomLayerOrder( other.mHasCustomLayerOrder )
32{
33 init();
34}
35
36void QgsLayerTree::init()
37{
38 connect( this, &QgsLayerTree::addedChildren, this, &QgsLayerTree::nodeAddedChildren );
39 connect( this, &QgsLayerTree::removedChildren, this, &QgsLayerTree::nodeRemovedChildren );
40}
41
42QList<QgsMapLayer *> QgsLayerTree::customLayerOrder() const
43{
44 return _qgis_listQPointerToRaw( mCustomLayerOrder );
45}
46
47void QgsLayerTree::setCustomLayerOrder( const QList<QgsMapLayer *> &customLayerOrder )
48{
49 QgsWeakMapLayerPointerList newOrder = _qgis_listRawToQPointer( customLayerOrder );
50
51 if ( newOrder == mCustomLayerOrder )
52 return;
53
54 mCustomLayerOrder = newOrder;
56
57 if ( mHasCustomLayerOrder )
58 emit layerOrderChanged();
59}
60
62{
63 QList<QgsMapLayer *> layers;
64
65 for ( const auto &layerId : customLayerOrder )
66 {
67 QgsLayerTreeLayer *nodeLayer = findLayer( layerId );
68 if ( nodeLayer )
69 {
70 // configuration from 2.x projects might have non spatial layers
71 QgsMapLayer *layer = nodeLayer->layer();
72 if ( !layer || !layer->isSpatial() )
73 {
74 continue;
75 }
76 layers.append( layer );
77 }
78 }
79 setCustomLayerOrder( layers );
80}
81
82QList<QgsMapLayer *> QgsLayerTree::layerOrder() const
83{
84 if ( mHasCustomLayerOrder )
85 {
86 return customLayerOrder();
87 }
88 else
89 {
91 }
92}
93
95{
96 return mHasCustomLayerOrder;
97}
98
100{
101 if ( hasCustomLayerOrder == mHasCustomLayerOrder )
102 return;
103
104 mHasCustomLayerOrder = hasCustomLayerOrder;
105
107 emit layerOrderChanged();
108}
109
110QList< QgsLayerTreeNode * > QgsLayerTree::layerAndCustomNodeOrder() const
111{
113}
114
115std::unique_ptr< QgsLayerTree > QgsLayerTree::readXml( const QDomElement &element, const QgsReadWriteContext &context ) // cppcheck-suppress duplInheritedMember
116{
117 auto tree = std::make_unique< QgsLayerTree >();
118
119 tree->readCommonXml( element );
120
121 tree->readChildrenFromXml( element, context );
122
123 return tree;
124}
125
126void QgsLayerTree::writeXml( QDomElement &parentElement, const QgsReadWriteContext &context )
127{
128 QDomDocument doc = parentElement.ownerDocument();
129 QDomElement elem = doc.createElement( QStringLiteral( "layer-tree-group" ) );
130
131 writeCommonXml( elem );
132
133 for ( QgsLayerTreeNode *node : std::as_const( mChildren ) )
134 node->writeXml( elem, context );
135
136 QDomElement customOrderElem = doc.createElement( QStringLiteral( "custom-order" ) );
137 customOrderElem.setAttribute( QStringLiteral( "enabled" ), mHasCustomLayerOrder ? 1 : 0 );
138 elem.appendChild( customOrderElem );
139
140 for ( QgsMapLayer *layer : std::as_const( mCustomLayerOrder ) )
141 {
142 // Safety belt, see https://github.com/qgis/QGIS/issues/26975
143 // Crash when deleting an item from the layout legend
144 if ( ! layer )
145 continue;
146 QDomElement layerElem = doc.createElement( QStringLiteral( "item" ) );
147 layerElem.appendChild( doc.createTextNode( layer->id() ) );
148 customOrderElem.appendChild( layerElem );
149 }
150
151 elem.appendChild( customOrderElem );
152
153 parentElement.appendChild( elem );
154}
155
157{
158 return new QgsLayerTree( *this );
159}
160
162{
164 setHasCustomLayerOrder( false );
165 setCustomLayerOrder( QStringList() );
166}
167
168void QgsLayerTree::nodeAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
169{
170 Q_ASSERT( node );
171
172 // collect layer IDs that have been added in order to put them into custom layer order
173 QList<QgsMapLayer *> layers;
174
175 QList<QgsLayerTreeNode *> children = node->children();
176 for ( int i = indexFrom; i <= indexTo; ++i )
177 {
178 QgsLayerTreeNode *child = children.at( i );
179 if ( QgsLayerTree::isLayer( child ) )
180 {
181 layers << QgsLayerTree::toLayer( child )->layer();
182 }
183 else if ( QgsLayerTree::isGroup( child ) )
184 {
185 const auto nodeLayers = QgsLayerTree::toGroup( child )->findLayers();
186 for ( QgsLayerTreeLayer *nodeL : nodeLayers )
187 layers << nodeL->layer();
188 }
189 }
190
191 for ( QgsMapLayer *layer : std::as_const( layers ) )
192 {
193 if ( !mCustomLayerOrder.contains( layer ) && layer )
194 mCustomLayerOrder.append( layer );
195 }
196
198 emit layerOrderChanged();
199}
200
201void QgsLayerTree::nodeRemovedChildren()
202{
203 QList<QgsMapLayer *> layers = customLayerOrder();
204 auto layer = layers.begin();
205
206 while ( layer != layers.end() )
207 {
208 if ( !findLayer( *layer ) )
209 layer = layers.erase( layer );
210 else
211 ++layer;
212 }
213
214 // we need to ensure that the customLayerOrderChanged signal is ALWAYS raised
215 // here, since that order HAS changed due to removal of the child!
216 // setCustomLayerOrder will only emit this signal when the layers list
217 // at this stage is different to the stored customer layer order. If this
218 // isn't the case (i.e. the lists ARE the same) then manually emit the
219 // signal
220 const bool emitSignal = _qgis_listRawToQPointer( layers ) == mCustomLayerOrder;
221
222 setCustomLayerOrder( layers );
223 if ( emitSignal )
225
226 emit layerOrderChanged();
227}
228
229void QgsLayerTree::addMissingLayers()
230{
231 bool changed = false;
232
233 const QList< QgsLayerTreeLayer * > layers = findLayers();
234 for ( const auto layer : layers )
235 {
236 if ( !mCustomLayerOrder.contains( layer->layer() ) &&
237 layer->layer() && layer->layer()->isSpatial() )
238 {
239 mCustomLayerOrder.append( layer->layer() );
240 changed = true;
241 }
242 }
243
244 if ( changed )
245 {
247 if ( mHasCustomLayerOrder )
248 emit layerOrderChanged();
249 }
250}
251
252void QgsLayerTree::readLayerOrderFromXml( const QDomElement &elem )
253{
254 QStringList order;
255
256 QDomElement customOrderElem = elem.firstChildElement( QStringLiteral( "custom-order" ) );
257 if ( !customOrderElem.isNull() )
258 {
259 setHasCustomLayerOrder( customOrderElem.attribute( QStringLiteral( "enabled" ) ).toInt() );
260
261 QDomElement itemElem = customOrderElem.firstChildElement( QStringLiteral( "item" ) );
262 while ( !itemElem.isNull() )
263 {
264 order.append( itemElem.text() );
265 itemElem = itemElem.nextSiblingElement( QStringLiteral( "item" ) );
266 }
267 }
268
269 setCustomLayerOrder( order );
270 addMissingLayers();
271}
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:80
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.