Skip to content
Permalink
Browse files

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.
  • Loading branch information
wonder-sk committed Jan 27, 2017
1 parent d259cdf commit 137eb3a0f93a74a04e17ef6929dfcb90ede9c9a9
@@ -1194,13 +1194,20 @@ QgsLayerTreeGroup {#qgis_api_break_3_0_QgsLayerTreeGroup}
- isVisible() is moved to QgsLayerTreeNode
- setVisible() is replaced by QgsLayerTreeNode::setItemVisibilityChecked()
- protected methods updateVisibilityFromChildren() and updateChildVisibility() removed
- readXml() and readChildrenFromXml() do not resolve layers from the layer IDs anymore. Call resolveReferences() or use readXml() override with QgsProject as the second argument.

QgsLayerTreeLayer {#qgis_api_break_3_0_QgsLayerTreeLayer}
-----------------

- setLayerName(), layerName() were renamed to setName(), name()
- isVisible() is moved to QgsLayerTreeNode
- setVisible() is replaced by QgsLayerTreeNode::setItemVisibilityChecked()
- readXml() does not resolve layer from the layer ID anymore. Call resolveReferences() or use readXml() override with QgsProject as the second argument.

QgsLayerTreeNode {#qgis_api_break_3_0_QgsLayerTreeNode}
----------------

- readXml() does not resolve layers from the layer IDs anymore. Call resolveReferences() or use readXml() override with QgsProject as the second argument.


QgsLayerTreeModel {#qgis_api_break_3_0_QgsLayerTreeMode}
@@ -58,11 +58,18 @@ class QgsLayerTreeGroup : QgsLayerTreeNode
//! Find group node with specified name. Searches recursively the whole sub-tree.
QgsLayerTreeGroup* findGroup( const QString& name );

//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error)
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error).
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
static QgsLayerTreeGroup* readXml( QDomElement& element ) /Factory/;
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error).
//! Also resolves textual references to layers from the project (calls resolveReferences() internally).
//! @note added in 3.0
static QgsLayerTreeGroup* readXml( QDomElement& element, const QgsProject* project ) /Factory/;

//! Write group (tree) as XML element <layer-tree-group> and add it to the given parent element
virtual void writeXml( QDomElement& parentElement );
//! Read children from XML and append them to the group.
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
void readChildrenFromXml( QDomElement& element );

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

//! Calls resolveReferences() on child tree nodes
//! @note added in 3.0
virtual void resolveReferences( const QgsProject* project );

//! Return whether the group is mutually exclusive (only one child can be checked at a time)
//! @note added in 2.12
bool isMutuallyExclusive() const;
@@ -1,14 +1,10 @@
/**
* Layer tree node points to a map layer.
*
* When using with existing QgsMapLayer instance, it is expected that the layer
* has been registered in QgsProject earlier.
*
* The node can exist also without a valid instance of a layer (just ID). That
* means the referenced layer does not need to be loaded in order to use it
* in layer tree. In such case, the node will start listening to map layer
* registry updates in expectation that the layer (identified by its ID) will
* be loaded later.
* in layer tree. In such case, resolveReferences() method can be called
* once the layer is loaded.
*
* A map layer is supposed to be present in one layer tree just once. It is
* however possible that temporarily a layer exists in one tree more than just
@@ -38,19 +34,23 @@ class QgsLayerTreeLayer : QgsLayerTreeNode
//! @note added in 3.0
void setName( const QString& n );

//! Read layer node from XML. Returns new instance.
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
static QgsLayerTreeLayer* readXml( QDomElement& element ) /Factory/;
//! Read layer node from XML. Returns new instance.
//! Also resolves textual references to layers from the project (calls resolveReferences() internally).
//! @note added in 3.0
static QgsLayerTreeLayer* readXml( QDomElement& element, const QgsProject* project ) /Factory/;

virtual void writeXml( QDomElement& parentElement );

virtual QString dump() const;

virtual QgsLayerTreeLayer* clone() const /Factory/;

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

signals:
//! emitted when a previously unavailable layer got loaded
@@ -83,8 +83,14 @@ class QgsLayerTreeNode : QObject
//! @note added in 3.0
virtual void setName( const QString& name ) = 0;

//! Read layer tree from XML. Returns new instance
static QgsLayerTreeNode* readXml( QDomElement& element ) /Factory/;
//! Read layer tree from XML. Returns new instance.
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
static QgsLayerTreeNode *readXml( QDomElement &element ) /Factory/;
//! Read layer tree from XML. Returns new instance.
//! Also resolves textual references to layers from the project (calls resolveReferences() internally).
//! @note added in 3.0
static QgsLayerTreeNode* readXml( QDomElement& element, const QgsProject* project ) /Factory/;

//! Write layer tree to XML
virtual void writeXml( QDomElement &parentElement ) = 0;

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

//! Turn textual references to layers into map layer object from project.
//! This method should be called after readXml()
//! @note added in 3.0
virtual void resolveReferences( const QgsProject* project ) = 0;

//! Returns whether a node is really visible (ie checked and all its ancestors checked as well)
//! @note added in 3.0
bool isVisible() const;
@@ -11573,7 +11573,7 @@ void QgisApp::writeProject( QDomDocument &doc )

QgsLayerTreeNode* clonedRoot = QgsProject::instance()->layerTreeRoot()->clone();
QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ) ); // convert absolute paths to relative paths if required
QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ), QgsProject::instance() ); // convert absolute paths to relative paths if required
QDomElement oldLegendElem = QgsLayerTreeUtils::writeOldLegend( doc, QgsLayerTree::toGroup( clonedRoot ),
mLayerTreeCanvasBridge->hasCustomLayerOrder(), mLayerTreeCanvasBridge->customLayerOrder() );
delete clonedRoot;
@@ -537,7 +537,7 @@ bool QgsComposerLegend::readXml( const QDomElement& itemElem, const QDomDocument
{
// QGIS >= 2.6
QDomElement layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree-group" ) );
setCustomLayerTree( QgsLayerTreeGroup::readXml( layerTreeElem ) );
setCustomLayerTree( QgsLayerTreeGroup::readXml( layerTreeElem, mComposition->project() ) );
}

//restore general composer item properties
@@ -18,7 +18,6 @@
#include "qgslayertree.h"
#include "qgslayertreeutils.h"
#include "qgsmaplayer.h"
#include "qgsproject.h"

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

QgsLayerTreeLayer*QgsLayerTreeGroup::insertLayer( int index, QgsMapLayer* layer )
QgsLayerTreeLayer* QgsLayerTreeGroup::insertLayer( int index, QgsMapLayer* layer )
{
if ( !layer || QgsProject::instance()->mapLayer( layer->id() ) != layer )
if ( !layer )
return nullptr;

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

QgsLayerTreeLayer* QgsLayerTreeGroup::addLayer( QgsMapLayer* layer )
{
if ( !layer || QgsProject::instance()->mapLayer( layer->id() ) != layer )
if ( !layer )
return nullptr;

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

QgsLayerTreeGroup* QgsLayerTreeGroup::readXml( QDomElement& element, const QgsProject* project )
{
QgsLayerTreeGroup* node = readXml( element );
if ( node )
node->resolveReferences( project );
return node;
}

void QgsLayerTreeGroup::writeXml( QDomElement& parentElement )
{
QDomDocument doc = parentElement.ownerDocument();
@@ -329,6 +336,12 @@ QgsLayerTreeGroup* QgsLayerTreeGroup::clone() const
return new QgsLayerTreeGroup( *this );
}

void QgsLayerTreeGroup::resolveReferences( const QgsProject* project )
{
Q_FOREACH ( QgsLayerTreeNode* node, mChildren )
node->resolveReferences( project );
}

static bool _nodeIsChecked( QgsLayerTreeNode* node )
{
return node->itemVisibilityChecked();
@@ -81,11 +81,18 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
//! Find group node with specified name. Searches recursively the whole sub-tree.
QgsLayerTreeGroup* findGroup( const QString& name );

//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error)
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error).
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
static QgsLayerTreeGroup* readXml( QDomElement& element );
//! Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on error).
//! Also resolves textual references to layers from the project (calls resolveReferences() internally).
//! @note added in 3.0
static QgsLayerTreeGroup* readXml( QDomElement& element, const QgsProject* project );

//! Write group (tree) as XML element <layer-tree-group> and add it to the given parent element
virtual void writeXml( QDomElement& parentElement ) override;
//! Read children from XML and append them to the group.
//! Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
void readChildrenFromXml( QDomElement& element );

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

//! Calls resolveReferences() on child tree nodes
//! @note added in 3.0
virtual void resolveReferences( const QgsProject* project ) override;

//! Check or uncheck a node and all its children (taking into account exclusion rules)
virtual void setItemVisibilityCheckedRecursive( bool checked ) override;

0 comments on commit 137eb3a

Please sign in to comment.
You can’t perform that action at this time.