Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgslayertreenode.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 "qgslayertreenode.h"
17 : :
18 : : #include "qgslayertree.h"
19 : : #include "qgslayertreeutils.h"
20 : :
21 : : #include <QDomElement>
22 : : #include <QStringList>
23 : :
24 : :
25 : 6 : QgsLayerTreeNode::QgsLayerTreeNode( QgsLayerTreeNode::NodeType t, bool checked )
26 : 6 : : mNodeType( t )
27 : 6 : , mChecked( checked )
28 : 6 : , mExpanded( true )
29 : 12 : {
30 : 6 : }
31 : :
32 : 0 : QgsLayerTreeNode::QgsLayerTreeNode( const QgsLayerTreeNode &other )
33 : 0 : : QObject( nullptr )
34 : 0 : , mNodeType( other.mNodeType )
35 : 0 : , mChecked( other.mChecked )
36 : 0 : , mExpanded( other.mExpanded )
37 : 0 : , mProperties( other.mProperties )
38 : 0 : {
39 : 0 : QList<QgsLayerTreeNode *> clonedChildren;
40 : :
41 : 0 : for ( QgsLayerTreeNode *child : std::as_const( other.mChildren ) )
42 : 0 : clonedChildren << child->clone();
43 : 0 : insertChildrenPrivate( -1, clonedChildren );
44 : 0 : }
45 : :
46 : 4 : QgsLayerTreeNode::~QgsLayerTreeNode()
47 : 4 : {
48 : 4 : qDeleteAll( mChildren );
49 : 4 : }
50 : :
51 : 1 : QList<QgsLayerTreeNode *> QgsLayerTreeNode::abandonChildren()
52 : : {
53 : 1 : const QList<QgsLayerTreeNode *> orphans { mChildren };
54 : 1 : mChildren.clear();
55 : 1 : for ( auto orphan : std::as_const( orphans ) )
56 : : {
57 : 0 : orphan->makeOrphan( );
58 : : }
59 : 1 : return orphans;
60 : 1 : }
61 : :
62 : 0 : void QgsLayerTreeNode::makeOrphan()
63 : : {
64 : 0 : disconnect();
65 : 0 : mParent = nullptr;
66 : 0 : }
67 : :
68 : 0 : QgsLayerTreeNode *QgsLayerTreeNode::readXml( QDomElement &element, const QgsReadWriteContext &context )
69 : : {
70 : 0 : QgsLayerTreeNode *node = nullptr;
71 : 0 : if ( element.tagName() == QLatin1String( "layer-tree-group" ) )
72 : 0 : node = QgsLayerTreeGroup::readXml( element, context );
73 : 0 : else if ( element.tagName() == QLatin1String( "layer-tree-layer" ) )
74 : 0 : node = QgsLayerTreeLayer::readXml( element, context );
75 : :
76 : 0 : return node;
77 : : }
78 : :
79 : 0 : QgsLayerTreeNode *QgsLayerTreeNode::readXml( QDomElement &element, const QgsProject *project )
80 : : {
81 : 0 : QgsReadWriteContext context;
82 : 0 : QgsPathResolver resolver;
83 : 0 : if ( project )
84 : 0 : resolver = project->pathResolver();
85 : 0 : context.setPathResolver( resolver );
86 : 0 : context.setProjectTranslator( const_cast<QgsProject *>( project ) );
87 : :
88 : 0 : QgsLayerTreeNode *node = readXml( element, context );
89 : 0 : if ( node )
90 : 0 : node->resolveReferences( project );
91 : 0 : return node;
92 : 0 : }
93 : :
94 : :
95 : 1 : void QgsLayerTreeNode::setItemVisibilityChecked( bool checked )
96 : : {
97 : 1 : if ( mChecked == checked )
98 : 1 : return;
99 : 0 : mChecked = checked;
100 : 0 : emit visibilityChanged( this );
101 : 1 : }
102 : :
103 : 0 : void QgsLayerTreeNode::setItemVisibilityCheckedRecursive( bool checked )
104 : : {
105 : 0 : setItemVisibilityChecked( checked );
106 : 0 : }
107 : :
108 : 0 : void QgsLayerTreeNode::setItemVisibilityCheckedParentRecursive( bool checked )
109 : : {
110 : 0 : setItemVisibilityChecked( checked );
111 : 0 : if ( mParent )
112 : 0 : mParent->setItemVisibilityCheckedParentRecursive( checked );
113 : 0 : }
114 : :
115 : 0 : bool QgsLayerTreeNode::isVisible() const
116 : : {
117 : 0 : return mChecked && ( !mParent || mParent->isVisible() );
118 : : }
119 : :
120 : :
121 : 0 : bool QgsLayerTreeNode::isExpanded() const
122 : : {
123 : 0 : return mExpanded;
124 : : }
125 : :
126 : 0 : bool QgsLayerTreeNode::isItemVisibilityCheckedRecursive() const
127 : : {
128 : 0 : if ( !mChecked )
129 : 0 : return false;
130 : 0 : const auto constMChildren = mChildren;
131 : 0 : for ( QgsLayerTreeNode *child : constMChildren )
132 : : {
133 : 0 : if ( !child->isItemVisibilityCheckedRecursive() )
134 : 0 : return false;
135 : : }
136 : :
137 : 0 : return true;
138 : 0 : }
139 : :
140 : 0 : bool QgsLayerTreeNode::isItemVisibilityUncheckedRecursive() const
141 : : {
142 : 0 : if ( mChecked )
143 : 0 : return false;
144 : 0 : const auto constMChildren = mChildren;
145 : 0 : for ( QgsLayerTreeNode *child : constMChildren )
146 : : {
147 : 0 : if ( !child->isItemVisibilityUncheckedRecursive() )
148 : 0 : return false;
149 : : }
150 : :
151 : 0 : return true;
152 : 0 : }
153 : :
154 : 0 : void fetchCheckedLayers( const QgsLayerTreeNode *node, QList<QgsMapLayer *> &layers )
155 : : {
156 : 0 : if ( QgsLayerTree::isLayer( node ) )
157 : : {
158 : 0 : const QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
159 : 0 : if ( nodeLayer->isVisible() )
160 : 0 : layers << nodeLayer->layer();
161 : 0 : }
162 : :
163 : 0 : const auto constChildren = node->children();
164 : 0 : for ( QgsLayerTreeNode *child : constChildren )
165 : 0 : fetchCheckedLayers( child, layers );
166 : 0 : }
167 : :
168 : 0 : QList<QgsMapLayer *> QgsLayerTreeNode::checkedLayers() const
169 : : {
170 : 0 : QList<QgsMapLayer *> layers;
171 : 0 : fetchCheckedLayers( this, layers );
172 : 0 : return layers;
173 : 0 : }
174 : :
175 : 0 : int QgsLayerTreeNode::depth() const
176 : : {
177 : 0 : int depth = 0;
178 : 0 : QgsLayerTreeNode *node = mParent;
179 : 0 : while ( node )
180 : : {
181 : 0 : node = node->parent();
182 : 0 : ++depth;
183 : : }
184 : 0 : return depth;
185 : : }
186 : :
187 : 0 : void QgsLayerTreeNode::setExpanded( bool expanded )
188 : : {
189 : 0 : if ( mExpanded == expanded )
190 : 0 : return;
191 : :
192 : 0 : mExpanded = expanded;
193 : 0 : emit expandedChanged( this, expanded );
194 : 0 : }
195 : :
196 : :
197 : 0 : void QgsLayerTreeNode::setCustomProperty( const QString &key, const QVariant &value )
198 : : {
199 : 0 : if ( !mProperties.contains( key ) || mProperties.value( key ) != value )
200 : : {
201 : 0 : mProperties.setValue( key, value );
202 : 0 : emit customPropertyChanged( this, key );
203 : 0 : }
204 : 0 : }
205 : :
206 : 0 : QVariant QgsLayerTreeNode::customProperty( const QString &key, const QVariant &defaultValue ) const
207 : : {
208 : 0 : return mProperties.value( key, defaultValue );
209 : : }
210 : :
211 : 0 : void QgsLayerTreeNode::removeCustomProperty( const QString &key )
212 : : {
213 : 0 : if ( mProperties.contains( key ) )
214 : : {
215 : 0 : mProperties.remove( key );
216 : 0 : emit customPropertyChanged( this, key );
217 : 0 : }
218 : 0 : }
219 : :
220 : 0 : QStringList QgsLayerTreeNode::customProperties() const
221 : : {
222 : 0 : return mProperties.keys();
223 : : }
224 : :
225 : 0 : void QgsLayerTreeNode::readCommonXml( QDomElement &element )
226 : : {
227 : 0 : mProperties.readXml( element );
228 : 0 : }
229 : :
230 : 0 : void QgsLayerTreeNode::writeCommonXml( QDomElement &element )
231 : : {
232 : 0 : QDomDocument doc( element.ownerDocument() );
233 : 0 : mProperties.writeXml( element, doc );
234 : 0 : }
235 : :
236 : 1 : void QgsLayerTreeNode::insertChildrenPrivate( int index, QList<QgsLayerTreeNode *> nodes )
237 : : {
238 : 1 : if ( nodes.isEmpty() )
239 : 0 : return;
240 : :
241 : 1 : const auto constNodes = nodes;
242 : 2 : for ( QgsLayerTreeNode *node : constNodes )
243 : : {
244 : : Q_ASSERT( !node->mParent );
245 : 1 : node->mParent = this;
246 : : }
247 : :
248 : 1 : if ( index < 0 || index >= mChildren.count() )
249 : 1 : index = mChildren.count();
250 : :
251 : 2 : for ( int i = 0; i < nodes.count(); ++i )
252 : : {
253 : 1 : QgsLayerTreeNode *node = nodes.at( i );
254 : :
255 : 1 : const QList<QgsLayerTreeNode *> orphans { node->abandonChildren() };
256 : :
257 : 1 : emit willAddChildren( this, index + i, index + i );
258 : 1 : mChildren.insert( index + i, node );
259 : 1 : emit addedChildren( this, index + i, index + i );
260 : :
261 : : // forward the signal towards the root
262 : 1 : connect( node, &QgsLayerTreeNode::willAddChildren, this, &QgsLayerTreeNode::willAddChildren );
263 : 1 : connect( node, &QgsLayerTreeNode::addedChildren, this, &QgsLayerTreeNode::addedChildren );
264 : 1 : connect( node, &QgsLayerTreeNode::willRemoveChildren, this, &QgsLayerTreeNode::willRemoveChildren );
265 : 1 : connect( node, &QgsLayerTreeNode::removedChildren, this, &QgsLayerTreeNode::removedChildren );
266 : 1 : connect( node, &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayerTreeNode::customPropertyChanged );
267 : 1 : connect( node, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeNode::visibilityChanged );
268 : 1 : connect( node, &QgsLayerTreeNode::expandedChanged, this, &QgsLayerTreeNode::expandedChanged );
269 : 1 : connect( node, &QgsLayerTreeNode::nameChanged, this, &QgsLayerTreeNode::nameChanged );
270 : :
271 : : // Now add children
272 : 1 : if ( ! orphans.isEmpty() )
273 : : {
274 : 0 : node->insertChildrenPrivate( -1, orphans );
275 : 0 : }
276 : :
277 : 1 : }
278 : 1 : }
279 : :
280 : 8 : void QgsLayerTreeNode::removeChildrenPrivate( int from, int count, bool destroy )
281 : : {
282 : 8 : if ( from < 0 || count <= 0 )
283 : 7 : return;
284 : :
285 : 1 : const int to = from + count - 1;
286 : 1 : if ( to >= mChildren.count() )
287 : 0 : return;
288 : :
289 : 6 : // Remove in reverse order
290 : 2 : while ( --count >= 0 )
291 : : {
292 : 1 : const int last { from + count };
293 : : Q_ASSERT( last >= 0 && last < mChildren.count( ) );
294 : 1 : QgsLayerTreeNode *node = mChildren.at( last );
295 : :
296 : : // Remove children first
297 : 1 : if ( ! node->children().isEmpty() )
298 : : {
299 : 0 : node->removeChildrenPrivate( 0, node->children().count( ), destroy );
300 : 0 : }
301 : :
302 : 1 : emit willRemoveChildren( this, last, last );
303 : 1 : node = mChildren.takeAt( last );
304 : 1 : if ( destroy )
305 : : {
306 : 1 : delete node;
307 : 1 : }
308 : : else
309 : : {
310 : 0 : node->makeOrphan();
311 : : }
312 : 1 : emit removedChildren( this, last, last );
313 : : }
314 : 8 : }
315 : :
316 : 0 : bool QgsLayerTreeNode::takeChild( QgsLayerTreeNode *node )
317 : : {
318 : 0 : int index = mChildren.indexOf( node );
319 : 0 : if ( index < 0 )
320 : 0 : return false;
321 : :
322 : 0 : int n = mChildren.size();
323 : :
324 : 0 : removeChildrenPrivate( index, 1, false );
325 : :
326 : 0 : return mChildren.size() < n;
327 : 0 : }
|