Skip to content

Commit 137eb3a

Browse files
committedJan 27, 2017
Make layer tree implementation independent from QgsProject::instance()
Another bit in the project refactoring work to get rid of dependencies on QgsProject singleton. Reading of layer trees from XML is now split into two phases: 1. read XML and keep layer IDs 2. resolve layer IDs to QgsMapLayer instances (using QgsProject) There are convenience methods to do both phases in one go.
1 parent d259cdf commit 137eb3a

21 files changed

+280
-116
lines changed
 

‎doc/api_break.dox

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,13 +1194,20 @@ QgsLayerTreeGroup {#qgis_api_break_3_0_QgsLayerTreeGroup}
11941194
- isVisible() is moved to QgsLayerTreeNode
11951195
- setVisible() is replaced by QgsLayerTreeNode::setItemVisibilityChecked()
11961196
- protected methods updateVisibilityFromChildren() and updateChildVisibility() removed
1197+
- readXml() and readChildrenFromXml() do not resolve layers from the layer IDs anymore. Call resolveReferences() or use readXml() override with QgsProject as the second argument.
11971198

11981199
QgsLayerTreeLayer {#qgis_api_break_3_0_QgsLayerTreeLayer}
11991200
-----------------
12001201

12011202
- setLayerName(), layerName() were renamed to setName(), name()
12021203
- isVisible() is moved to QgsLayerTreeNode
12031204
- setVisible() is replaced by QgsLayerTreeNode::setItemVisibilityChecked()
1205+
- readXml() does not resolve layer from the layer ID anymore. Call resolveReferences() or use readXml() override with QgsProject as the second argument.
1206+
1207+
QgsLayerTreeNode {#qgis_api_break_3_0_QgsLayerTreeNode}
1208+
----------------
1209+
1210+
- readXml() does not resolve layers from the layer IDs anymore. Call resolveReferences() or use readXml() override with QgsProject as the second argument.
12041211

12051212

12061213
QgsLayerTreeModel {#qgis_api_break_3_0_QgsLayerTreeMode}

‎python/core/layertree/qgslayertreegroup.sip

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,18 @@ class QgsLayerTreeGroup : QgsLayerTreeNode
5858
//! Find group node with specified name. Searches recursively the whole sub-tree.
5959
QgsLayerTreeGroup* findGroup( const QString& name );
6060

61-
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error)
61+
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error).
62+
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
6263
static QgsLayerTreeGroup* readXml( QDomElement& element ) /Factory/;
64+
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error).
65+
//! Also resolves textual references to layers from the project (calls resolveReferences() internally).
66+
//! @note added in 3.0
67+
static QgsLayerTreeGroup* readXml( QDomElement& element, const QgsProject* project ) /Factory/;
68+
6369
//! Write group (tree) as XML element <layer-tree-group> and add it to the given parent element
6470
virtual void writeXml( QDomElement& parentElement );
6571
//! Read children from XML and append them to the group.
72+
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
6673
void readChildrenFromXml( QDomElement& element );
6774

6875
//! Return text representation of the tree. For debugging purposes only.
@@ -71,6 +78,10 @@ class QgsLayerTreeGroup : QgsLayerTreeNode
7178
//! Return a clone of the group. The children are cloned too.
7279
virtual QgsLayerTreeGroup* clone() const /Factory/;
7380

81+
//! Calls resolveReferences() on child tree nodes
82+
//! @note added in 3.0
83+
virtual void resolveReferences( const QgsProject* project );
84+
7485
//! Return whether the group is mutually exclusive (only one child can be checked at a time)
7586
//! @note added in 2.12
7687
bool isMutuallyExclusive() const;

‎python/core/layertree/qgslayertreelayer.sip

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
/**
22
* Layer tree node points to a map layer.
33
*
4-
* When using with existing QgsMapLayer instance, it is expected that the layer
5-
* has been registered in QgsProject earlier.
6-
*
74
* The node can exist also without a valid instance of a layer (just ID). That
85
* means the referenced layer does not need to be loaded in order to use it
9-
* in layer tree. In such case, the node will start listening to map layer
10-
* registry updates in expectation that the layer (identified by its ID) will
11-
* be loaded later.
6+
* in layer tree. In such case, resolveReferences() method can be called
7+
* once the layer is loaded.
128
*
139
* A map layer is supposed to be present in one layer tree just once. It is
1410
* however possible that temporarily a layer exists in one tree more than just
@@ -38,19 +34,23 @@ class QgsLayerTreeLayer : QgsLayerTreeNode
3834
//! @note added in 3.0
3935
void setName( const QString& n );
4036

37+
//! Read layer node from XML. Returns new instance.
38+
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
4139
static QgsLayerTreeLayer* readXml( QDomElement& element ) /Factory/;
40+
//! Read layer node from XML. Returns new instance.
41+
//! Also resolves textual references to layers from the project (calls resolveReferences() internally).
42+
//! @note added in 3.0
43+
static QgsLayerTreeLayer* readXml( QDomElement& element, const QgsProject* project ) /Factory/;
44+
4245
virtual void writeXml( QDomElement& parentElement );
4346

4447
virtual QString dump() const;
4548

4649
virtual QgsLayerTreeLayer* clone() const /Factory/;
4750

48-
protected slots:
49-
void registryLayersAdded( const QList<QgsMapLayer*>& layers );
50-
void registryLayersWillBeRemoved( const QStringList& layerIds );
51-
//! Emits a nameChanged() signal if layer's name has changed
51+
//! Resolves reference to layer from stored layer ID (if it has not been resolved already)
5252
//! @note added in 3.0
53-
void layerNameChanged();
53+
virtual void resolveReferences( const QgsProject* project );
5454

5555
signals:
5656
//! emitted when a previously unavailable layer got loaded

‎python/core/layertree/qgslayertreenode.sip

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,14 @@ class QgsLayerTreeNode : QObject
8383
//! @note added in 3.0
8484
virtual void setName( const QString& name ) = 0;
8585

86-
//! Read layer tree from XML. Returns new instance
87-
static QgsLayerTreeNode* readXml( QDomElement& element ) /Factory/;
86+
//! Read layer tree from XML. Returns new instance.
87+
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
88+
static QgsLayerTreeNode *readXml( QDomElement &element ) /Factory/;
89+
//! Read layer tree from XML. Returns new instance.
90+
//! Also resolves textual references to layers from the project (calls resolveReferences() internally).
91+
//! @note added in 3.0
92+
static QgsLayerTreeNode* readXml( QDomElement& element, const QgsProject* project ) /Factory/;
93+
8894
//! Write layer tree to XML
8995
virtual void writeXml( QDomElement &parentElement ) = 0;
9096

@@ -94,6 +100,11 @@ class QgsLayerTreeNode : QObject
94100
//! Create a copy of the node. Returns new instance
95101
virtual QgsLayerTreeNode *clone() const = 0 /Factory/;
96102

103+
//! Turn textual references to layers into map layer object from project.
104+
//! This method should be called after readXml()
105+
//! @note added in 3.0
106+
virtual void resolveReferences( const QgsProject* project ) = 0;
107+
97108
//! Returns whether a node is really visible (ie checked and all its ancestors checked as well)
98109
//! @note added in 3.0
99110
bool isVisible() const;

‎src/app/qgisapp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11573,7 +11573,7 @@ void QgisApp::writeProject( QDomDocument &doc )
1157311573

1157411574
QgsLayerTreeNode* clonedRoot = QgsProject::instance()->layerTreeRoot()->clone();
1157511575
QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
11576-
QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ) ); // convert absolute paths to relative paths if required
11576+
QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ), QgsProject::instance() ); // convert absolute paths to relative paths if required
1157711577
QDomElement oldLegendElem = QgsLayerTreeUtils::writeOldLegend( doc, QgsLayerTree::toGroup( clonedRoot ),
1157811578
mLayerTreeCanvasBridge->hasCustomLayerOrder(), mLayerTreeCanvasBridge->customLayerOrder() );
1157911579
delete clonedRoot;

‎src/core/composer/qgscomposerlegend.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ bool QgsComposerLegend::readXml( const QDomElement& itemElem, const QDomDocument
537537
{
538538
// QGIS >= 2.6
539539
QDomElement layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree-group" ) );
540-
setCustomLayerTree( QgsLayerTreeGroup::readXml( layerTreeElem ) );
540+
setCustomLayerTree( QgsLayerTreeGroup::readXml( layerTreeElem, mComposition->project() ) );
541541
}
542542

543543
//restore general composer item properties

‎src/core/layertree/qgslayertreegroup.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "qgslayertree.h"
1919
#include "qgslayertreeutils.h"
2020
#include "qgsmaplayer.h"
21-
#include "qgsproject.h"
2221

2322
#include <QDomElement>
2423
#include <QStringList>
@@ -73,9 +72,9 @@ QgsLayerTreeGroup* QgsLayerTreeGroup::addGroup( const QString &name )
7372
return grp;
7473
}
7574

76-
QgsLayerTreeLayer*QgsLayerTreeGroup::insertLayer( int index, QgsMapLayer* layer )
75+
QgsLayerTreeLayer* QgsLayerTreeGroup::insertLayer( int index, QgsMapLayer* layer )
7776
{
78-
if ( !layer || QgsProject::instance()->mapLayer( layer->id() ) != layer )
77+
if ( !layer )
7978
return nullptr;
8079

8180
QgsLayerTreeLayer* ll = new QgsLayerTreeLayer( layer );
@@ -85,7 +84,7 @@ QgsLayerTreeLayer*QgsLayerTreeGroup::insertLayer( int index, QgsMapLayer* layer
8584

8685
QgsLayerTreeLayer* QgsLayerTreeGroup::addLayer( QgsMapLayer* layer )
8786
{
88-
if ( !layer || QgsProject::instance()->mapLayer( layer->id() ) != layer )
87+
if ( !layer )
8988
return nullptr;
9089

9190
QgsLayerTreeLayer* ll = new QgsLayerTreeLayer( layer );
@@ -276,6 +275,14 @@ QgsLayerTreeGroup* QgsLayerTreeGroup::readXml( QDomElement& element )
276275
return groupNode;
277276
}
278277

278+
QgsLayerTreeGroup* QgsLayerTreeGroup::readXml( QDomElement& element, const QgsProject* project )
279+
{
280+
QgsLayerTreeGroup* node = readXml( element );
281+
if ( node )
282+
node->resolveReferences( project );
283+
return node;
284+
}
285+
279286
void QgsLayerTreeGroup::writeXml( QDomElement& parentElement )
280287
{
281288
QDomDocument doc = parentElement.ownerDocument();
@@ -329,6 +336,12 @@ QgsLayerTreeGroup* QgsLayerTreeGroup::clone() const
329336
return new QgsLayerTreeGroup( *this );
330337
}
331338

339+
void QgsLayerTreeGroup::resolveReferences( const QgsProject* project )
340+
{
341+
Q_FOREACH ( QgsLayerTreeNode* node, mChildren )
342+
node->resolveReferences( project );
343+
}
344+
332345
static bool _nodeIsChecked( QgsLayerTreeNode* node )
333346
{
334347
return node->itemVisibilityChecked();

‎src/core/layertree/qgslayertreegroup.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,18 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
8181
//! Find group node with specified name. Searches recursively the whole sub-tree.
8282
QgsLayerTreeGroup* findGroup( const QString& name );
8383

84-
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error)
84+
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error).
85+
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
8586
static QgsLayerTreeGroup* readXml( QDomElement& element );
87+
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error).
88+
//! Also resolves textual references to layers from the project (calls resolveReferences() internally).
89+
//! @note added in 3.0
90+
static QgsLayerTreeGroup* readXml( QDomElement& element, const QgsProject* project );
91+
8692
//! Write group (tree) as XML element <layer-tree-group> and add it to the given parent element
8793
virtual void writeXml( QDomElement& parentElement ) override;
8894
//! Read children from XML and append them to the group.
95+
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
8996
void readChildrenFromXml( QDomElement& element );
9097

9198
//! Return text representation of the tree. For debugging purposes only.
@@ -94,6 +101,10 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
94101
//! Return a clone of the group. The children are cloned too.
95102
virtual QgsLayerTreeGroup* clone() const override;
96103

104+
//! Calls resolveReferences() on child tree nodes
105+
//! @note added in 3.0
106+
virtual void resolveReferences( const QgsProject* project ) override;
107+
97108
//! Check or uncheck a node and all its children (taking into account exclusion rules)
98109
virtual void setItemVisibilityCheckedRecursive( bool checked ) override;
99110

0 commit comments

Comments
 (0)
Please sign in to comment.