Skip to content

Commit

Permalink
Use a path resolver class instead of QgsProject::instance() in map la…
Browse files Browse the repository at this point in the history
…yers

A new class QgsPathResolver is introduced for conversion between absolute
and relative paths when reading/writing XML.

Cleaned up code in layer definition file support (.qlr) to better handle
relative/absolute path conversion.
  • Loading branch information
wonder-sk committed Feb 16, 2017
1 parent f706c71 commit 5f5c1dd
Show file tree
Hide file tree
Showing 21 changed files with 405 additions and 300 deletions.
4 changes: 3 additions & 1 deletion doc/api_break.dox
Expand Up @@ -1214,6 +1214,7 @@ QgsLayerDefinition {#qgis_api_break_3_0_QgsLayerDefinition}
------------------

- loadLayerDefinition() now also requires QgsProject as the second argument
- loadLayerDefinition() and exportLayerDefinition() variants that take QDomDocument as the first argument now expect QgsPathResolver as the last argument


QgsLayerPropertiesWidget {#qgis_api_break_3_0_QgsLayerPropertiesWidget}
Expand Down Expand Up @@ -1335,7 +1336,7 @@ screenUpdateRequested() were removed. These members have had no effect for a num
- capitaliseLayerName() was renamed to capitalizeLayerName() <!--#spellok-->
- asLayerDefinition(), fromLayerDefinition(), fromLayerDefinitionFile() were moved to QgsLayerDefinition class and renamed to exportLayerDefinitionLayers() resp. loadLayerDefinitionLayers()
- loadNamedStyleFromDb() was renamed to loadNamedStyleFromDatabase()

- readLayerXml() and writeLayerXml() expect QgsPathResolver reference as the last argument

QgsMapOverviewCanvas {#qgis_api_break_3_0_QgsMapOverviewCanvas}
--------------------
Expand Down Expand Up @@ -1570,6 +1571,7 @@ QgsProject {#qgis_api_break_3_0_QgsProject}
- read( const QFileInfo& file ) was replaced by read( const QString& filename ).
- write( const QFileInfo& file ) was replaced by write( const QString& filename ).
- createEmbeddedLayer() does not take vectorLayerList as the third parameter anymore.
- writePath() does not accept second argument (relativeBasePath) anymore. Use QgsPathResolver instead.


QgsProjectPropertyValue {#qgis_api_break_3_0_QgsProjectPropertyValue}
Expand Down
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -107,6 +107,7 @@
%Include qgspaintenginehack.sip
%Include qgspainting.sip
%Include qgspallabeling.sip
%Include qgspathresolver.sip
%Include qgspluginlayer.sip
%Include qgspluginlayerregistry.sip
%Include qgspoint.sip
Expand Down
8 changes: 4 additions & 4 deletions python/core/qgslayerdefinition.sip
Expand Up @@ -12,12 +12,12 @@ class QgsLayerDefinition
%End
public:
static bool loadLayerDefinition( const QString & path, QgsProject* project, QgsLayerTreeGroup* rootGroup, QString &errorMessage /Out/ );
static bool loadLayerDefinition( QDomDocument doc, QgsProject* project, QgsLayerTreeGroup* rootGroup, QString &errorMessage /Out/ );
static bool loadLayerDefinition( QDomDocument doc, QgsProject* project, QgsLayerTreeGroup* rootGroup, QString &errorMessage /Out/, const QgsPathResolver& pathResolver );
static bool exportLayerDefinition( QString path, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage /Out/ );
static bool exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage, const QString& relativeBasePath = QString::null );
static bool exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage /Out/, const QgsPathResolver& pathResolver );

static QDomDocument exportLayerDefinitionLayers( const QList<QgsMapLayer*>& layers, const QString& relativeBasePath = QString::null );
static QList<QgsMapLayer*> loadLayerDefinitionLayers( QDomDocument& document ) /Factory/;
static QDomDocument exportLayerDefinitionLayers( const QList<QgsMapLayer*>& layers, const QgsPathResolver& pathResolver );
static QList<QgsMapLayer*> loadLayerDefinitionLayers( QDomDocument& document, const QgsPathResolver& pathResolver ) /Factory/;
static QList<QgsMapLayer*> loadLayerDefinitionLayers( const QString &qlrfile ) /Factory/;

/**
Expand Down
34 changes: 2 additions & 32 deletions python/core/qgsmaplayer.sip
Expand Up @@ -321,39 +321,9 @@ class QgsMapLayer : QObject
*/
virtual bool isSpatial() const;

/** Sets state from Dom document
@param layerElement The Dom element corresponding to ``maplayer'' tag
@note
bool readLayerXml( const QDomElement& layerElement, const QgsPathResolver& pathResolver );

The Dom node corresponds to a Dom document project file XML element read
by QgsProject.

This, in turn, calls readXml(), which is over-rideable by sub-classes so
that they can read their own specific state from the given Dom node.

Invoked by QgsProject::read().

@returns true if successful
*/
bool readLayerXml( const QDomElement& layerElement );

/** Stores state in Dom node
* @param layerElement is a Dom element corresponding to ``maplayer'' tag
* @param document is a the dom document being written
* @param relativeBasePath base path for relative paths
* @note
*
* The Dom node corresponds to a Dom document project file XML element to be
* written by QgsProject.
*
* This, in turn, calls writeXml(), which is over-rideable by sub-classes so
* that they can write their own specific state to the given Dom node.
*
* Invoked by QgsProject::write().
*
* @returns true if successful
*/
bool writeLayerXml( QDomElement& layerElement, QDomDocument& document, const QString& relativeBasePath = QString::null ) const;
bool writeLayerXml( QDomElement& layerElement, QDomDocument& document, const QgsPathResolver& pathResolver ) const;

/** Set a custom property for layer. Properties are stored in a map and saved in project file.
* @see customProperty()
Expand Down
15 changes: 15 additions & 0 deletions python/core/qgspathresolver.sip
@@ -0,0 +1,15 @@

class QgsPathResolver
{
%TypeHeaderCode
#include <qgspathresolver.h>
%End

public:
explicit QgsPathResolver( const QString& baseFileName = QString() );

QString writePath( const QString& filename ) const;

QString readPath( const QString& filename ) const;

};
4 changes: 3 additions & 1 deletion python/core/qgsproject.sip
Expand Up @@ -233,12 +233,14 @@ class QgsProject : QObject, QgsExpressionContextGenerator
*/
void dumpProperties() const;

QgsPathResolver pathResolver() const;

/**
* Prepare a filename to save it to the project file.
* Creates an absolute or relative path according to the project settings.
* Paths written to the project file should be prepared with this method.
*/
QString writePath( const QString& filename, const QString& relativeBasePath = QString::null ) const;
QString writePath( const QString& filename ) const;

/** Turn filename read from the project file to an absolute path */
QString readPath( QString filename ) const;
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -187,6 +187,7 @@ SET(QGIS_CORE_SRCS
qgspaintenginehack.cpp
qgspainting.cpp
qgspallabeling.cpp
qgspathresolver.cpp
qgspluginlayer.cpp
qgspluginlayerregistry.cpp
qgspoint.cpp
Expand Down Expand Up @@ -727,6 +728,7 @@ SET(QGIS_CORE_HDRS
qgspaintenginehack.h
qgspainting.h
qgspallabeling.h
qgspathresolver.h
qgspluginlayerregistry.h
qgspointlocator.h
qgsprojectbadlayerhandler.h
Expand Down
27 changes: 12 additions & 15 deletions src/core/qgslayerdefinition.cpp
Expand Up @@ -22,6 +22,7 @@
#include "qgslayertree.h"
#include "qgslogger.h"
#include "qgsmaplayer.h"
#include "qgspathresolver.h"
#include "qgspluginlayer.h"
#include "qgspluginlayerregistry.h"
#include "qgsproject.h"
Expand All @@ -48,10 +49,10 @@ bool QgsLayerDefinition::loadLayerDefinition( const QString &path, QgsProject* p
QFileInfo fileinfo( file );
QDir::setCurrent( fileinfo.absoluteDir().path() );

return loadLayerDefinition( doc, project, rootGroup, errorMessage );
return loadLayerDefinition( doc, project, rootGroup, errorMessage, QgsPathResolver( path ) );
}

bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsProject* project, QgsLayerTreeGroup *rootGroup, QString &errorMessage )
bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsProject* project, QgsLayerTreeGroup *rootGroup, QString &errorMessage, const QgsPathResolver& pathResolver )
{
Q_UNUSED( errorMessage );

Expand Down Expand Up @@ -140,7 +141,7 @@ bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsProject* proj
loadInLegend = false;
}

QList<QgsMapLayer*> layers = QgsLayerDefinition::loadLayerDefinitionLayers( doc );
QList<QgsMapLayer*> layers = QgsLayerDefinition::loadLayerDefinitionLayers( doc, pathResolver );

project->addMapLayers( layers, loadInLegend );

Expand Down Expand Up @@ -179,18 +180,16 @@ bool QgsLayerDefinition::exportLayerDefinition( QString path, const QList<QgsLay
return false;
}

QFileInfo fileinfo( file );

QDomDocument doc( QStringLiteral( "qgis-layer-definition" ) );
if ( !exportLayerDefinition( doc, selectedTreeNodes, errorMessage, fileinfo.canonicalFilePath() ) )
if ( !exportLayerDefinition( doc, selectedTreeNodes, errorMessage, QgsPathResolver( path ) ) )
return false;

QTextStream qlayerstream( &file );
doc.save( qlayerstream, 2 );
return true;
}

bool QgsLayerDefinition::exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage, const QString& relativeBasePath )
bool QgsLayerDefinition::exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage, const QgsPathResolver& pathResolver )
{
Q_UNUSED( errorMessage );
QDomElement qgiselm = doc.createElement( QStringLiteral( "qlr" ) );
Expand All @@ -209,14 +208,14 @@ bool QgsLayerDefinition::exportLayerDefinition( QDomDocument doc, const QList<Qg
Q_FOREACH ( QgsLayerTreeLayer* layer, layers )
{
QDomElement layerelm = doc.createElement( QStringLiteral( "maplayer" ) );
layer->layer()->writeLayerXml( layerelm, doc, relativeBasePath );
layer->layer()->writeLayerXml( layerelm, doc, pathResolver );
layerselm.appendChild( layerelm );
}
qgiselm.appendChild( layerselm );
return true;
}

QDomDocument QgsLayerDefinition::exportLayerDefinitionLayers( const QList<QgsMapLayer *>& layers, const QString& relativeBasePath )
QDomDocument QgsLayerDefinition::exportLayerDefinitionLayers( const QList<QgsMapLayer *>& layers, const QgsPathResolver& pathResolver )
{
QDomDocument doc( QStringLiteral( "qgis-layer-definition" ) );
QDomElement qgiselm = doc.createElement( QStringLiteral( "qlr" ) );
Expand All @@ -225,14 +224,14 @@ QDomDocument QgsLayerDefinition::exportLayerDefinitionLayers( const QList<QgsMap
Q_FOREACH ( QgsMapLayer* layer, layers )
{
QDomElement layerelm = doc.createElement( QStringLiteral( "maplayer" ) );
layer->writeLayerXml( layerelm, doc, relativeBasePath );
layer->writeLayerXml( layerelm, doc, pathResolver );
layerselm.appendChild( layerelm );
}
qgiselm.appendChild( layerselm );
return doc;
}

QList<QgsMapLayer*> QgsLayerDefinition::loadLayerDefinitionLayers( QDomDocument& document )
QList<QgsMapLayer*> QgsLayerDefinition::loadLayerDefinitionLayers( QDomDocument& document, const QgsPathResolver& pathResolver )
{
QList<QgsMapLayer*> layers;
QDomNodeList layernodes = document.elementsByTagName( QStringLiteral( "maplayer" ) );
Expand Down Expand Up @@ -262,7 +261,7 @@ QList<QgsMapLayer*> QgsLayerDefinition::loadLayerDefinitionLayers( QDomDocument&
if ( !layer )
continue;

if ( layer->readLayerXml( layerElem ) )
if ( layer->readLayerXml( layerElem, pathResolver ) )
{
layers << layer;
}
Expand All @@ -286,9 +285,7 @@ QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayers( const QStrin
return QList<QgsMapLayer*>();
}

QFileInfo fileinfo( file );
QDir::setCurrent( fileinfo.absoluteDir().path() );
return QgsLayerDefinition::loadLayerDefinitionLayers( doc );
return QgsLayerDefinition::loadLayerDefinitionLayers( doc, QgsPathResolver( qlrfile ) );
}


Expand Down
9 changes: 5 additions & 4 deletions src/core/qgslayerdefinition.h
Expand Up @@ -27,6 +27,7 @@ class QDomDocument;
class QgsLayerTreeGroup;
class QgsLayerTreeNode;
class QgsMapLayer;
class QgsPathResolver;
class QgsProject;

/** \ingroup core
Expand All @@ -42,11 +43,11 @@ class CORE_EXPORT QgsLayerDefinition
//! Loads the QLR at path into QGIS. New layers are added to given project into layer tree specified by rootGroup
static bool loadLayerDefinition( const QString & path, QgsProject* project, QgsLayerTreeGroup* rootGroup, QString &errorMessage );
//! Loads the QLR from the XML document. New layers are added to given project into layer tree specified by rootGroup
static bool loadLayerDefinition( QDomDocument doc, QgsProject* project, QgsLayerTreeGroup* rootGroup, QString &errorMessage );
static bool loadLayerDefinition( QDomDocument doc, QgsProject* project, QgsLayerTreeGroup* rootGroup, QString &errorMessage, const QgsPathResolver& pathResolver );
//! Export the selected layer tree nodes to a QLR file
static bool exportLayerDefinition( QString path, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage );
//! Export the selected layer tree nodes to a QLR-XML document
static bool exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage, const QString& relativeBasePath = QString::null );
static bool exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage, const QgsPathResolver& pathResolver );

/** Returns the given layer as a layer definition document
* Layer definitions store the data source as well as styling and custom properties.
Expand All @@ -56,12 +57,12 @@ class CORE_EXPORT QgsLayerDefinition
* This is a low-level routine that does not write layer tree.
* @see exportLayerDefinition()
*/
static QDomDocument exportLayerDefinitionLayers( const QList<QgsMapLayer*>& layers, const QString& relativeBasePath = QString::null );
static QDomDocument exportLayerDefinitionLayers( const QList<QgsMapLayer*>& layers, const QgsPathResolver& pathResolver );

//! Creates new layers from a layer definition document.
//! This is a low-level routine that does not resolve layer ID conflicts, dependencies and joins
//! @see loadLayerDefinition()
static QList<QgsMapLayer*> loadLayerDefinitionLayers( QDomDocument& document );
static QList<QgsMapLayer*> loadLayerDefinitionLayers( QDomDocument& document, const QgsPathResolver& pathResolver );
//! Creates new layers from a layer definition file (.QLR)
//! This is a low-level routine that does not resolve layer ID conflicts, dependencies and joins
//! @see loadLayerDefinition()
Expand Down

0 comments on commit 5f5c1dd

Please sign in to comment.