[bugfix] Pass QgsReadWriteContext into project XML r/w

Or we miss the path resolver and we do not read/write
relative paths correctly

Fixes #17116
This commit is contained in:
Alessandro Pasotti 2017-11-07 18:17:48 +01:00
parent 8aa8c30bbf
commit 7aa24f6906
25 changed files with 97 additions and 59 deletions

View File

@ -8,6 +8,7 @@
class QgsComposerItemGroup: QgsComposerItem class QgsComposerItemGroup: QgsComposerItem
{ {
%Docstring %Docstring

View File

@ -9,6 +9,7 @@
class QgsComposerObject: QObject, QgsExpressionContextGenerator class QgsComposerObject: QObject, QgsExpressionContextGenerator
{ {
%Docstring %Docstring

View File

@ -122,7 +122,7 @@ class QgsLayerTree : QgsLayerTreeGroup
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End
static QgsLayerTree *readXml( QDomElement &element ); static QgsLayerTree *readXml( QDomElement &element, const QgsReadWriteContext &context );
%Docstring %Docstring
Load the layer tree from an XML element. Load the layer tree from an XML element.
It is not required that layers are loaded at this point. It is not required that layers are loaded at this point.
@ -141,7 +141,7 @@ class QgsLayerTree : QgsLayerTreeGroup
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End
virtual void writeXml( QDomElement &parentElement ); virtual void writeXml( QDomElement &parentElement, const QgsReadWriteContext &context );
virtual QgsLayerTree *clone() const /Factory/; virtual QgsLayerTree *clone() const /Factory/;

View File

@ -138,14 +138,14 @@ class QgsLayerTreeGroup : QgsLayerTreeNode
:rtype: QgsLayerTreeGroup :rtype: QgsLayerTreeGroup
%End %End
static QgsLayerTreeGroup *readXml( QDomElement &element ) /Factory/; static QgsLayerTreeGroup *readXml( QDomElement &element, const QgsReadWriteContext &context ) /Factory/;
%Docstring %Docstring
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. Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
:rtype: QgsLayerTreeGroup :rtype: QgsLayerTreeGroup
%End %End
static QgsLayerTreeGroup *readXml( QDomElement &element, const QgsProject *project ) /Factory/; static QgsLayerTreeGroup *readXml( QDomElement &element, const QgsProject *project, const QgsReadWriteContext &context ) /Factory/;
%Docstring %Docstring
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).
Also resolves textual references to layers from the project (calls resolveReferences() internally). Also resolves textual references to layers from the project (calls resolveReferences() internally).
@ -153,12 +153,12 @@ class QgsLayerTreeGroup : QgsLayerTreeNode
:rtype: QgsLayerTreeGroup :rtype: QgsLayerTreeGroup
%End %End
virtual void writeXml( QDomElement &parentElement ); virtual void writeXml( QDomElement &parentElement, const QgsReadWriteContext &context );
%Docstring %Docstring
Write group (tree) as XML element <layer-tree-group> and add it to the given parent element Write group (tree) as XML element <layer-tree-group> and add it to the given parent element
%End %End
void readChildrenFromXml( QDomElement &element ); void readChildrenFromXml( QDomElement &element, const QgsReadWriteContext &context );
%Docstring %Docstring
Read children from XML and append them to the group. Read children from XML and append them to the group.
Does not resolve textual references to layers. Call resolveReferences() afterwards to do it. Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.

View File

@ -63,14 +63,14 @@ class QgsLayerTreeLayer : QgsLayerTreeNode
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End
static QgsLayerTreeLayer *readXml( QDomElement &element ) /Factory/; static QgsLayerTreeLayer *readXml( QDomElement &element, const QgsReadWriteContext &context ) /Factory/;
%Docstring %Docstring
Read layer node from XML. Returns new instance. Read layer node from XML. Returns new instance.
Does not resolve textual references to layers. Call resolveReferences() afterwards to do it. Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
:rtype: QgsLayerTreeLayer :rtype: QgsLayerTreeLayer
%End %End
static QgsLayerTreeLayer *readXml( QDomElement &element, const QgsProject *project ) /Factory/; static QgsLayerTreeLayer *readXml( QDomElement &element, const QgsProject *project, const QgsReadWriteContext &context ) /Factory/;
%Docstring %Docstring
Read layer node from XML. Returns new instance. Read layer node from XML. Returns new instance.
Also resolves textual references to layers from the project (calls resolveReferences() internally). Also resolves textual references to layers from the project (calls resolveReferences() internally).
@ -78,7 +78,7 @@ class QgsLayerTreeLayer : QgsLayerTreeNode
:rtype: QgsLayerTreeLayer :rtype: QgsLayerTreeLayer
%End %End
virtual void writeXml( QDomElement &parentElement ); virtual void writeXml( QDomElement &parentElement, const QgsReadWriteContext &context );
virtual QString dump() const; virtual QString dump() const;

View File

@ -111,7 +111,7 @@ Get list of children of the node. Children are owned by the parent
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End
static QgsLayerTreeNode *readXml( QDomElement &element ) /Factory/; static QgsLayerTreeNode *readXml( QDomElement &element, const QgsReadWriteContext &context ) /Factory/;
%Docstring %Docstring
Read layer tree from XML. Returns new instance. Read layer tree from XML. Returns new instance.
Does not resolve textual references to layers. Call resolveReferences() afterwards to do it. Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
@ -126,7 +126,7 @@ Get list of children of the node. Children are owned by the parent
:rtype: QgsLayerTreeNode :rtype: QgsLayerTreeNode
%End %End
virtual void writeXml( QDomElement &parentElement ) = 0; virtual void writeXml( QDomElement &parentElement, const QgsReadWriteContext &context ) = 0;
%Docstring %Docstring
Write layer tree to XML Write layer tree to XML
%End %End

View File

@ -170,7 +170,7 @@ void QgsProjectLayerGroupDialog::changeProjectFile()
QDomElement layerTreeElem = projectDom.documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) ); QDomElement layerTreeElem = projectDom.documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
if ( !layerTreeElem.isNull() ) if ( !layerTreeElem.isNull() )
{ {
mRootGroup->readChildrenFromXml( layerTreeElem ); mRootGroup->readChildrenFromXml( layerTreeElem, QgsReadWriteContext() );
} }
else else
{ {

View File

@ -429,7 +429,6 @@ bool QgsComposerArrow::writeXml( QDomElement &elem, QDomDocument &doc ) const
QgsReadWriteContext context; QgsReadWriteContext context;
context.setPathResolver( pathResolver ); context.setPathResolver( pathResolver );
// absolute paths to relative // absolute paths to relative
QString startMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mStartMarkerFile, pathResolver ); QString startMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mStartMarkerFile, pathResolver );
QString endMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mEndMarkerFile, pathResolver ); QString endMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mEndMarkerFile, pathResolver );

View File

@ -143,6 +143,12 @@ void QgsComposerItem::setSelected( bool s )
bool QgsComposerItem::_writeXml( QDomElement &itemElem, QDomDocument &doc ) const bool QgsComposerItem::_writeXml( QDomElement &itemElem, QDomDocument &doc ) const
{ {
QgsPathResolver pathResolver;
if ( composition() )
pathResolver = composition()->project()->pathResolver();
QgsReadWriteContext context;
context.setPathResolver( pathResolver );
if ( itemElem.isNull() ) if ( itemElem.isNull() )
{ {
return false; return false;

View File

@ -20,6 +20,8 @@
#include "qgis_core.h" #include "qgis_core.h"
#include "qgis.h" #include "qgis.h"
#include "qgscomposeritem.h" #include "qgscomposeritem.h"
#include "qgsreadwritecontext.h"
#include <QSet> #include <QSet>
/** /**

View File

@ -344,6 +344,12 @@ bool QgsComposerLegend::writeXml( QDomElement &elem, QDomDocument &doc ) const
return false; return false;
} }
QgsPathResolver pathResolver;
if ( mComposition )
pathResolver = mComposition->project()->pathResolver();
QgsReadWriteContext context;
context.setPathResolver( pathResolver );
QDomElement composerLegendElem = doc.createElement( QStringLiteral( "ComposerLegend" ) ); QDomElement composerLegendElem = doc.createElement( QStringLiteral( "ComposerLegend" ) );
elem.appendChild( composerLegendElem ); elem.appendChild( composerLegendElem );
@ -389,7 +395,7 @@ bool QgsComposerLegend::writeXml( QDomElement &elem, QDomDocument &doc ) const
if ( mCustomLayerTree ) if ( mCustomLayerTree )
{ {
// if not using auto-update - store the custom layer tree // if not using auto-update - store the custom layer tree
mCustomLayerTree->writeXml( composerLegendElem ); mCustomLayerTree->writeXml( composerLegendElem, context );
} }
if ( mLegendFilterByMap ) if ( mLegendFilterByMap )
@ -408,6 +414,12 @@ bool QgsComposerLegend::readXml( const QDomElement &itemElem, const QDomDocument
return false; return false;
} }
QgsPathResolver pathResolver;
if ( mComposition )
pathResolver = mComposition->project()->pathResolver();
QgsReadWriteContext context;
context.setPathResolver( pathResolver );
//read general properties //read general properties
mTitle = itemElem.attribute( QStringLiteral( "title" ) ); mTitle = itemElem.attribute( QStringLiteral( "title" ) );
mSettings.setTitle( mTitle ); mSettings.setTitle( mTitle );
@ -479,7 +491,7 @@ bool QgsComposerLegend::readXml( const QDomElement &itemElem, const QDomDocument
if ( !layerTreeElem.isNull() ) if ( !layerTreeElem.isNull() )
{ {
std::unique_ptr< QgsLayerTree > tree( QgsLayerTree::readXml( layerTreeElem ) ); std::unique_ptr< QgsLayerTree > tree( QgsLayerTree::readXml( layerTreeElem, context ) );
if ( mComposition ) if ( mComposition )
tree->resolveReferences( mComposition->project(), true ); tree->resolveReferences( mComposition->project(), true );
setCustomLayerTree( tree.release() ); setCustomLayerTree( tree.release() );

View File

@ -272,6 +272,7 @@ bool QgsComposerNodesItem::moveNode( const int index, QPointF pt )
bool QgsComposerNodesItem::readXml( const QDomElement &itemElem, bool QgsComposerNodesItem::readXml( const QDomElement &itemElem,
const QDomDocument &doc ) const QDomDocument &doc )
{ {
// restore general composer item properties // restore general composer item properties
const QDomNodeList composerItemList = itemElem.elementsByTagName( QStringLiteral( "ComposerItem" ) ); const QDomNodeList composerItemList = itemElem.elementsByTagName( QStringLiteral( "ComposerItem" ) );
if ( !composerItemList.isEmpty() ) if ( !composerItemList.isEmpty() )

View File

@ -22,6 +22,8 @@
#include "qgsobjectcustomproperties.h" #include "qgsobjectcustomproperties.h"
#include "qgsexpressioncontextgenerator.h" #include "qgsexpressioncontextgenerator.h"
#include "qgspropertycollection.h" #include "qgspropertycollection.h"
#include "qgsreadwritecontext.h"
#include <QObject> #include <QObject>
#include <QDomNode> #include <QDomNode>
#include <QMap> #include <QMap>

View File

@ -99,18 +99,18 @@ void QgsLayerTree::setHasCustomLayerOrder( bool hasCustomLayerOrder )
emit layerOrderChanged(); emit layerOrderChanged();
} }
QgsLayerTree *QgsLayerTree::readXml( QDomElement &element ) QgsLayerTree *QgsLayerTree::readXml( QDomElement &element, const QgsReadWriteContext &context )
{ {
QgsLayerTree *tree = new QgsLayerTree(); QgsLayerTree *tree = new QgsLayerTree();
tree->readCommonXml( element ); tree->readCommonXml( element );
tree->readChildrenFromXml( element ); tree->readChildrenFromXml( element, context );
return tree; return tree;
} }
void QgsLayerTree::writeXml( QDomElement &parentElement ) void QgsLayerTree::writeXml( QDomElement &parentElement, const QgsReadWriteContext &context )
{ {
QDomDocument doc = parentElement.ownerDocument(); QDomDocument doc = parentElement.ownerDocument();
QDomElement elem = doc.createElement( QStringLiteral( "layer-tree-group" ) ); QDomElement elem = doc.createElement( QStringLiteral( "layer-tree-group" ) );
@ -118,7 +118,7 @@ void QgsLayerTree::writeXml( QDomElement &parentElement )
writeCommonXml( elem ); writeCommonXml( elem );
Q_FOREACH ( QgsLayerTreeNode *node, mChildren ) Q_FOREACH ( QgsLayerTreeNode *node, mChildren )
node->writeXml( elem ); node->writeXml( elem, context );
QDomElement customOrderElem = doc.createElement( QStringLiteral( "custom-order" ) ); QDomElement customOrderElem = doc.createElement( QStringLiteral( "custom-order" ) );
customOrderElem.setAttribute( QStringLiteral( "enabled" ), mHasCustomLayerOrder ? 1 : 0 ); customOrderElem.setAttribute( QStringLiteral( "enabled" ), mHasCustomLayerOrder ? 1 : 0 );

View File

@ -172,7 +172,7 @@ class CORE_EXPORT QgsLayerTree : public QgsLayerTreeGroup
* *
* \since QGIS 3.0 * \since QGIS 3.0
*/ */
static QgsLayerTree *readXml( QDomElement &element ); static QgsLayerTree *readXml( QDomElement &element, const QgsReadWriteContext &context );
/** /**
* Load the layer order from an XML element. * Load the layer order from an XML element.
@ -182,7 +182,7 @@ class CORE_EXPORT QgsLayerTree : public QgsLayerTreeGroup
*/ */
void readLayerOrderFromXml( const QDomElement &doc ); void readLayerOrderFromXml( const QDomElement &doc );
virtual void writeXml( QDomElement &parentElement ) override; virtual void writeXml( QDomElement &parentElement, const QgsReadWriteContext &context ) override;
virtual QgsLayerTree *clone() const override SIP_FACTORY; virtual QgsLayerTree *clone() const override SIP_FACTORY;

View File

@ -249,7 +249,7 @@ QgsLayerTreeGroup *QgsLayerTreeGroup::findGroup( const QString &name )
return nullptr; return nullptr;
} }
QgsLayerTreeGroup *QgsLayerTreeGroup::readXml( QDomElement &element ) QgsLayerTreeGroup *QgsLayerTreeGroup::readXml( QDomElement &element, const QgsReadWriteContext &context )
{ {
if ( element.tagName() != QLatin1String( "layer-tree-group" ) ) if ( element.tagName() != QLatin1String( "layer-tree-group" ) )
return nullptr; return nullptr;
@ -265,22 +265,22 @@ QgsLayerTreeGroup *QgsLayerTreeGroup::readXml( QDomElement &element )
groupNode->readCommonXml( element ); groupNode->readCommonXml( element );
groupNode->readChildrenFromXml( element ); groupNode->readChildrenFromXml( element, context );
groupNode->setIsMutuallyExclusive( isMutuallyExclusive, mutuallyExclusiveChildIndex ); groupNode->setIsMutuallyExclusive( isMutuallyExclusive, mutuallyExclusiveChildIndex );
return groupNode; return groupNode;
} }
QgsLayerTreeGroup *QgsLayerTreeGroup::readXml( QDomElement &element, const QgsProject *project ) QgsLayerTreeGroup *QgsLayerTreeGroup::readXml( QDomElement &element, const QgsProject *project, const QgsReadWriteContext &context )
{ {
QgsLayerTreeGroup *node = readXml( element ); QgsLayerTreeGroup *node = readXml( element, context );
if ( node ) if ( node )
node->resolveReferences( project ); node->resolveReferences( project );
return node; return node;
} }
void QgsLayerTreeGroup::writeXml( QDomElement &parentElement ) void QgsLayerTreeGroup::writeXml( QDomElement &parentElement, const QgsReadWriteContext &context )
{ {
QDomDocument doc = parentElement.ownerDocument(); QDomDocument doc = parentElement.ownerDocument();
QDomElement elem = doc.createElement( QStringLiteral( "layer-tree-group" ) ); QDomElement elem = doc.createElement( QStringLiteral( "layer-tree-group" ) );
@ -296,18 +296,18 @@ void QgsLayerTreeGroup::writeXml( QDomElement &parentElement )
writeCommonXml( elem ); writeCommonXml( elem );
Q_FOREACH ( QgsLayerTreeNode *node, mChildren ) Q_FOREACH ( QgsLayerTreeNode *node, mChildren )
node->writeXml( elem ); node->writeXml( elem, context );
parentElement.appendChild( elem ); parentElement.appendChild( elem );
} }
void QgsLayerTreeGroup::readChildrenFromXml( QDomElement &element ) void QgsLayerTreeGroup::readChildrenFromXml( QDomElement &element, const QgsReadWriteContext &context )
{ {
QList<QgsLayerTreeNode *> nodes; QList<QgsLayerTreeNode *> nodes;
QDomElement childElem = element.firstChildElement(); QDomElement childElem = element.firstChildElement();
while ( !childElem.isNull() ) while ( !childElem.isNull() )
{ {
QgsLayerTreeNode *newNode = QgsLayerTreeNode::readXml( childElem ); QgsLayerTreeNode *newNode = QgsLayerTreeNode::readXml( childElem, context );
if ( newNode ) if ( newNode )
nodes << newNode; nodes << newNode;

View File

@ -145,25 +145,25 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
* 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. * Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
*/ */
static QgsLayerTreeGroup *readXml( QDomElement &element ) SIP_FACTORY; static QgsLayerTreeGroup *readXml( QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;
/** /**
* 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).
* Also resolves textual references to layers from the project (calls resolveReferences() internally). * Also resolves textual references to layers from the project (calls resolveReferences() internally).
* \since QGIS 3.0 * \since QGIS 3.0
*/ */
static QgsLayerTreeGroup *readXml( QDomElement &element, const QgsProject *project ) SIP_FACTORY; static QgsLayerTreeGroup *readXml( QDomElement &element, const QgsProject *project, const QgsReadWriteContext &context ) SIP_FACTORY;
/** /**
* Write group (tree) as XML element <layer-tree-group> and add it to the given parent element * Write group (tree) as XML element <layer-tree-group> and add it to the given parent element
*/ */
virtual void writeXml( QDomElement &parentElement ) override; virtual void writeXml( QDomElement &parentElement, const QgsReadWriteContext &context ) override;
/** /**
* Read children from XML and append them to the group. * Read children from XML and append them to the group.
* Does not resolve textual references to layers. Call resolveReferences() afterwards to do it. * Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
*/ */
void readChildrenFromXml( QDomElement &element ); void readChildrenFromXml( QDomElement &element, const QgsReadWriteContext &context );
/** /**
* Return text representation of the tree. For debugging purposes only. * Return text representation of the tree. For debugging purposes only.

View File

@ -97,8 +97,9 @@ void QgsLayerTreeLayer::setName( const QString &n )
} }
} }
QgsLayerTreeLayer *QgsLayerTreeLayer::readXml( QDomElement &element ) QgsLayerTreeLayer *QgsLayerTreeLayer::readXml( QDomElement &element, const QgsReadWriteContext &context )
{ {
Q_UNUSED( context );
if ( element.tagName() != QLatin1String( "layer-tree-layer" ) ) if ( element.tagName() != QLatin1String( "layer-tree-layer" ) )
return nullptr; return nullptr;
@ -106,7 +107,7 @@ QgsLayerTreeLayer *QgsLayerTreeLayer::readXml( QDomElement &element )
QString layerName = element.attribute( QStringLiteral( "name" ) ); QString layerName = element.attribute( QStringLiteral( "name" ) );
QString providerKey = element.attribute( QStringLiteral( "providerKey" ) ); QString providerKey = element.attribute( QStringLiteral( "providerKey" ) );
QString source = element.attribute( QStringLiteral( "source" ) ); QString source = context.pathResolver().readPath( element.attribute( QStringLiteral( "source" ) ) );
Qt::CheckState checked = QgsLayerTreeUtils::checkStateFromXml( element.attribute( QStringLiteral( "checked" ) ) ); Qt::CheckState checked = QgsLayerTreeUtils::checkStateFromXml( element.attribute( QStringLiteral( "checked" ) ) );
bool isExpanded = ( element.attribute( QStringLiteral( "expanded" ), QStringLiteral( "1" ) ) == QLatin1String( "1" ) ); bool isExpanded = ( element.attribute( QStringLiteral( "expanded" ), QStringLiteral( "1" ) ) == QLatin1String( "1" ) );
@ -121,15 +122,15 @@ QgsLayerTreeLayer *QgsLayerTreeLayer::readXml( QDomElement &element )
return nodeLayer; return nodeLayer;
} }
QgsLayerTreeLayer *QgsLayerTreeLayer::readXml( QDomElement &element, const QgsProject *project ) QgsLayerTreeLayer *QgsLayerTreeLayer::readXml( QDomElement &element, const QgsProject *project, const QgsReadWriteContext &context )
{ {
QgsLayerTreeLayer *node = readXml( element ); QgsLayerTreeLayer *node = readXml( element, context );
if ( node ) if ( node )
node->resolveReferences( project ); node->resolveReferences( project );
return node; return node;
} }
void QgsLayerTreeLayer::writeXml( QDomElement &parentElement ) void QgsLayerTreeLayer::writeXml( QDomElement &parentElement, const QgsReadWriteContext &context )
{ {
QDomDocument doc = parentElement.ownerDocument(); QDomDocument doc = parentElement.ownerDocument();
QDomElement elem = doc.createElement( QStringLiteral( "layer-tree-layer" ) ); QDomElement elem = doc.createElement( QStringLiteral( "layer-tree-layer" ) );
@ -138,7 +139,7 @@ void QgsLayerTreeLayer::writeXml( QDomElement &parentElement )
if ( mRef ) if ( mRef )
{ {
elem.setAttribute( QStringLiteral( "source" ), mRef->publicSource() ); elem.setAttribute( QStringLiteral( "source" ), context.pathResolver().writePath( mRef->publicSource() ) );
elem.setAttribute( QStringLiteral( "providerKey" ), mRef->dataProvider() ? mRef->dataProvider()->name() : QString() ); elem.setAttribute( QStringLiteral( "providerKey" ), mRef->dataProvider() ? mRef->dataProvider()->name() : QString() );
} }

View File

@ -20,6 +20,7 @@
#include "qgis.h" #include "qgis.h"
#include "qgslayertreenode.h" #include "qgslayertreenode.h"
#include "qgsmaplayerref.h" #include "qgsmaplayerref.h"
#include "qgsreadwritecontext.h"
class QgsMapLayer; class QgsMapLayer;
@ -73,16 +74,16 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode
* Read layer node from XML. Returns new instance. * Read layer node from XML. Returns new instance.
* Does not resolve textual references to layers. Call resolveReferences() afterwards to do it. * Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
*/ */
static QgsLayerTreeLayer *readXml( QDomElement &element ) SIP_FACTORY; static QgsLayerTreeLayer *readXml( QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;
/** /**
* Read layer node from XML. Returns new instance. * Read layer node from XML. Returns new instance.
* Also resolves textual references to layers from the project (calls resolveReferences() internally). * Also resolves textual references to layers from the project (calls resolveReferences() internally).
* \since QGIS 3.0 * \since QGIS 3.0
*/ */
static QgsLayerTreeLayer *readXml( QDomElement &element, const QgsProject *project ) SIP_FACTORY; static QgsLayerTreeLayer *readXml( QDomElement &element, const QgsProject *project, const QgsReadWriteContext &context ) SIP_FACTORY;
virtual void writeXml( QDomElement &parentElement ) override; virtual void writeXml( QDomElement &parentElement, const QgsReadWriteContext &context ) override;
virtual QString dump() const override; virtual QString dump() const override;

View File

@ -999,7 +999,7 @@ QMimeData *QgsLayerTreeModel::mimeData( const QModelIndexList &indexes ) const
QDomDocument doc; QDomDocument doc;
QDomElement rootElem = doc.createElement( QStringLiteral( "layer_tree_model_data" ) ); QDomElement rootElem = doc.createElement( QStringLiteral( "layer_tree_model_data" ) );
Q_FOREACH ( QgsLayerTreeNode *node, nodesFinal ) Q_FOREACH ( QgsLayerTreeNode *node, nodesFinal )
node->writeXml( rootElem ); node->writeXml( rootElem, QgsReadWriteContext() );
doc.appendChild( rootElem ); doc.appendChild( rootElem );
QString txt = doc.toString(); QString txt = doc.toString();

View File

@ -47,20 +47,26 @@ QgsLayerTreeNode::~QgsLayerTreeNode()
qDeleteAll( mChildren ); qDeleteAll( mChildren );
} }
QgsLayerTreeNode *QgsLayerTreeNode::readXml( QDomElement &element ) QgsLayerTreeNode *QgsLayerTreeNode::readXml( QDomElement &element, const QgsReadWriteContext &context )
{ {
QgsLayerTreeNode *node = nullptr; QgsLayerTreeNode *node = nullptr;
if ( element.tagName() == QLatin1String( "layer-tree-group" ) ) if ( element.tagName() == QLatin1String( "layer-tree-group" ) )
node = QgsLayerTreeGroup::readXml( element ); node = QgsLayerTreeGroup::readXml( element, context );
else if ( element.tagName() == QLatin1String( "layer-tree-layer" ) ) else if ( element.tagName() == QLatin1String( "layer-tree-layer" ) )
node = QgsLayerTreeLayer::readXml( element ); node = QgsLayerTreeLayer::readXml( element, context );
return node; return node;
} }
QgsLayerTreeNode *QgsLayerTreeNode::readXml( QDomElement &element, const QgsProject *project ) QgsLayerTreeNode *QgsLayerTreeNode::readXml( QDomElement &element, const QgsProject *project )
{ {
QgsLayerTreeNode *node = readXml( element ); QgsReadWriteContext context;
QgsPathResolver resolver;
if ( project )
resolver = project->pathResolver();
context.setPathResolver( resolver );
QgsLayerTreeNode *node = readXml( element, context );
if ( node ) if ( node )
node->resolveReferences( project ); node->resolveReferences( project );
return node; return node;

View File

@ -20,6 +20,7 @@
#include <QObject> #include <QObject>
#include "qgsobjectcustomproperties.h" #include "qgsobjectcustomproperties.h"
#include "qgsreadwritecontext.h"
#include "qgis.h" #include "qgis.h"
class QDomElement; class QDomElement;
@ -126,7 +127,7 @@ class CORE_EXPORT QgsLayerTreeNode : public QObject
* Read layer tree from XML. Returns new instance. * Read layer tree from XML. Returns new instance.
* Does not resolve textual references to layers. Call resolveReferences() afterwards to do it. * Does not resolve textual references to layers. Call resolveReferences() afterwards to do it.
*/ */
static QgsLayerTreeNode *readXml( QDomElement &element ) SIP_FACTORY; static QgsLayerTreeNode *readXml( QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;
/** /**
* Read layer tree from XML. Returns new instance. * Read layer tree from XML. Returns new instance.
@ -136,7 +137,7 @@ class CORE_EXPORT QgsLayerTreeNode : public QObject
static QgsLayerTreeNode *readXml( QDomElement &element, const QgsProject *project ) SIP_FACTORY; static QgsLayerTreeNode *readXml( QDomElement &element, const QgsProject *project ) SIP_FACTORY;
//! Write layer tree to XML //! Write layer tree to XML
virtual void writeXml( QDomElement &parentElement ) = 0; virtual void writeXml( QDomElement &parentElement, const QgsReadWriteContext &context ) = 0;
//! Return string with layer tree structure. For debug purposes only //! Return string with layer tree structure. For debug purposes only
virtual QString dump() const = 0; virtual QString dump() const = 0;

View File

@ -448,8 +448,9 @@ void QgsLayoutItemLegend::updateLegend()
updateFilterByMap( false ); updateFilterByMap( false );
} }
bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &composerLegendElem, QDomDocument &doc, const QgsReadWriteContext & ) const bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &composerLegendElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
{ {
//write general properties //write general properties
composerLegendElem.setAttribute( QStringLiteral( "title" ), mTitle ); composerLegendElem.setAttribute( QStringLiteral( "title" ), mTitle );
composerLegendElem.setAttribute( QStringLiteral( "titleAlignment" ), QString::number( static_cast< int >( mSettings.titleAlignment() ) ) ); composerLegendElem.setAttribute( QStringLiteral( "titleAlignment" ), QString::number( static_cast< int >( mSettings.titleAlignment() ) ) );
@ -492,7 +493,7 @@ bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &composerLegendE
if ( mCustomLayerTree ) if ( mCustomLayerTree )
{ {
// if not using auto-update - store the custom layer tree // if not using auto-update - store the custom layer tree
mCustomLayerTree->writeXml( composerLegendElem ); mCustomLayerTree->writeXml( composerLegendElem, context );
} }
if ( mLegendFilterByMap ) if ( mLegendFilterByMap )
@ -504,7 +505,7 @@ bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &composerLegendE
return true; return true;
} }
bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext & ) bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
{ {
//read general properties //read general properties
mTitle = itemElem.attribute( QStringLiteral( "title" ) ); mTitle = itemElem.attribute( QStringLiteral( "title" ) );
@ -586,7 +587,7 @@ bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem
if ( !layerTreeElem.isNull() ) if ( !layerTreeElem.isNull() )
{ {
std::unique_ptr< QgsLayerTree > tree( QgsLayerTree::readXml( layerTreeElem ) ); std::unique_ptr< QgsLayerTree > tree( QgsLayerTree::readXml( layerTreeElem, context ) );
if ( mLayout ) if ( mLayout )
tree->resolveReferences( mLayout->project(), true ); tree->resolveReferences( mLayout->project(), true );
setCustomLayerTree( tree.release() ); setCustomLayerTree( tree.release() );

View File

@ -141,7 +141,7 @@ bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsProject *proj
bool loadInLegend = true; bool loadInLegend = true;
if ( !layerTreeElem.isNull() ) if ( !layerTreeElem.isNull() )
{ {
root->readChildrenFromXml( layerTreeElem ); root->readChildrenFromXml( layerTreeElem, context );
loadInLegend = false; loadInLegend = false;
} }
@ -208,7 +208,7 @@ bool QgsLayerDefinition::exportLayerDefinition( QDomDocument doc, const QList<Qg
QgsLayerTreeNode *newnode = node->clone(); QgsLayerTreeNode *newnode = node->clone();
root->addChildNode( newnode ); root->addChildNode( newnode );
} }
root->writeXml( qgiselm ); root->writeXml( qgiselm, context );
QDomElement layerselm = doc.createElement( QStringLiteral( "maplayers" ) ); QDomElement layerselm = doc.createElement( QStringLiteral( "maplayers" ) );
QList<QgsLayerTreeLayer *> layers = root->findLayers(); QList<QgsLayerTreeLayer *> layers = root->findLayers();

View File

@ -924,7 +924,7 @@ bool QgsProject::readProjectFile( const QString &filename )
QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) ); QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
if ( !layerTreeElem.isNull() ) if ( !layerTreeElem.isNull() )
{ {
mRootGroup->readChildrenFromXml( layerTreeElem ); mRootGroup->readChildrenFromXml( layerTreeElem, context );
} }
else else
{ {
@ -1040,6 +1040,7 @@ bool QgsProject::readProjectFile( const QString &filename )
void QgsProject::loadEmbeddedNodes( QgsLayerTreeGroup *group ) void QgsProject::loadEmbeddedNodes( QgsLayerTreeGroup *group )
{ {
Q_FOREACH ( QgsLayerTreeNode *child, group->children() ) Q_FOREACH ( QgsLayerTreeNode *child, group->children() )
{ {
if ( QgsLayerTree::isGroup( child ) ) if ( QgsLayerTree::isGroup( child ) )
@ -1050,7 +1051,6 @@ void QgsProject::loadEmbeddedNodes( QgsLayerTreeGroup *group )
// make sure to convert the path from relative to absolute // make sure to convert the path from relative to absolute
QString projectPath = readPath( childGroup->customProperty( QStringLiteral( "embedded_project" ) ).toString() ); QString projectPath = readPath( childGroup->customProperty( QStringLiteral( "embedded_project" ) ).toString() );
childGroup->setCustomProperty( QStringLiteral( "embedded_project" ), projectPath ); childGroup->setCustomProperty( QStringLiteral( "embedded_project" ), projectPath );
QgsLayerTreeGroup *newGroup = createEmbeddedGroup( childGroup->name(), projectPath, childGroup->customProperty( QStringLiteral( "embedded-invisible-layers" ) ).toStringList() ); QgsLayerTreeGroup *newGroup = createEmbeddedGroup( childGroup->name(), projectPath, childGroup->customProperty( QStringLiteral( "embedded-invisible-layers" ) ).toStringList() );
if ( newGroup ) if ( newGroup )
{ {
@ -1344,7 +1344,8 @@ bool QgsProject::writeProjectFile( const QString &filename )
QgsLayerTreeNode *clonedRoot = mRootGroup->clone(); QgsLayerTreeNode *clonedRoot = mRootGroup->clone();
QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) ); QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ), this ); // convert absolute paths to relative paths if required QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ), this ); // convert absolute paths to relative paths if required
clonedRoot->writeXml( qgisNode );
clonedRoot->writeXml( qgisNode, context );
delete clonedRoot; delete clonedRoot;
mSnappingConfig.writeProject( *doc ); mSnappingConfig.writeProject( *doc );
@ -1860,6 +1861,9 @@ QgsLayerTreeGroup *QgsProject::createEmbeddedGroup( const QString &groupName, co
return nullptr; return nullptr;
} }
QgsReadWriteContext context;
context.setPathResolver( pathResolver() );
// store identify disabled layers of the embedded project // store identify disabled layers of the embedded project
QSet<QString> embeddedIdentifyDisabledLayers; QSet<QString> embeddedIdentifyDisabledLayers;
QDomElement disabledLayersElem = projectDocument.documentElement().firstChildElement( QStringLiteral( "properties" ) ).firstChildElement( QStringLiteral( "Identify" ) ).firstChildElement( QStringLiteral( "disabledLayers" ) ); QDomElement disabledLayersElem = projectDocument.documentElement().firstChildElement( QStringLiteral( "properties" ) ).firstChildElement( QStringLiteral( "Identify" ) ).firstChildElement( QStringLiteral( "disabledLayers" ) );
@ -1877,7 +1881,7 @@ QgsLayerTreeGroup *QgsProject::createEmbeddedGroup( const QString &groupName, co
QDomElement layerTreeElem = projectDocument.documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) ); QDomElement layerTreeElem = projectDocument.documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
if ( !layerTreeElem.isNull() ) if ( !layerTreeElem.isNull() )
{ {
root->readChildrenFromXml( layerTreeElem ); root->readChildrenFromXml( layerTreeElem, context );
} }
else else
{ {