Skip to content

Commit

Permalink
Make layer tree implementation independent from QgsProject::instance()
Browse files Browse the repository at this point in the history
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 137eb3a
Show file tree
Hide file tree
Showing 21 changed files with 280 additions and 116 deletions.
7 changes: 7 additions & 0 deletions doc/api_break.dox
Expand Up @@ -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}
Expand Down
13 changes: 12 additions & 1 deletion python/core/layertree/qgslayertreegroup.sip
Expand Up @@ -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.
Expand All @@ -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;
Expand Down
22 changes: 11 additions & 11 deletions python/core/layertree/qgslayertreelayer.sip
@@ -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
Expand Down Expand Up @@ -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
Expand Down
15 changes: 13 additions & 2 deletions python/core/layertree/qgslayertreenode.sip
Expand Up @@ -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;

Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/core/composer/qgscomposerlegend.cpp
Expand Up @@ -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
Expand Down
21 changes: 17 additions & 4 deletions src/core/layertree/qgslayertreegroup.cpp
Expand Up @@ -18,7 +18,6 @@
#include "qgslayertree.h"
#include "qgslayertreeutils.h"
#include "qgsmaplayer.h"
#include "qgsproject.h"

#include <QDomElement>
#include <QStringList>
Expand Down Expand Up @@ -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 );
Expand All @@ -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 );
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
13 changes: 12 additions & 1 deletion src/core/layertree/qgslayertreegroup.h
Expand Up @@ -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.
Expand All @@ -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;

Expand Down

0 comments on commit 137eb3a

Please sign in to comment.