Skip to content

Commit

Permalink
Update loose layer matching to use layer source, name and provider
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Mar 22, 2017
1 parent 22b3307 commit 95c3072
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 19 deletions.
22 changes: 17 additions & 5 deletions python/core/layertree/qgslayertreelayer.sip
Expand Up @@ -21,17 +21,29 @@ class QgsLayerTreeLayer : QgsLayerTreeNode
%TypeHeaderCode
#include <qgslayertreelayer.h>
%End
public:

//! Parameters for loose layer matching
struct LayerMatchParams
{
//! Layer public source
QString source;
//! Layer name
QString name;
//! Provider
QString providerKey;
};

public:
explicit QgsLayerTreeLayer( QgsMapLayer* layer );

/**
* Creates a layer node which will attach to a layer with a matching
* QgsMapLayer::publicSource(). This can be used for "looser" layer matching,
* Creates a layer node which will attach to a layer with matching
* parameters. This can be used for "looser" layer matching,
* avoiding the usual layer id check in favour of attaching to any layer
* with an equal source.
* with an equal source/name/provider.
*/
static QgsLayerTreeLayer* createLayerFromSource( const QString& source ) /Factory/;
static QgsLayerTreeLayer* createLayerFromParams( const LayerMatchParams& source ) /Factory/;

explicit QgsLayerTreeLayer( const QString& layerId, const QString& name = QString() );

Expand All @@ -52,7 +64,7 @@ class QgsLayerTreeLayer : QgsLayerTreeNode
* avoiding the usual layer id check in favour of attaching to any layer
* with an equal source.
*/
void attachToSource( const QString& source );
void attachToSource( const LayerMatchParams &source );

QString layerName() const;
void setLayerName( const QString& n );
Expand Down
75 changes: 68 additions & 7 deletions src/core/layertree/qgslayertreelayer.cpp
Expand Up @@ -18,7 +18,10 @@
#include "qgslayertreeutils.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerregistry.h"

#include "qgsvectorlayer.h"
#include "qgsrasterlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsrasterdataprovider.h"

QgsLayerTreeLayer::QgsLayerTreeLayer( QgsMapLayer *layer )
: QgsLayerTreeNode( NodeLayer )
Expand Down Expand Up @@ -50,7 +53,7 @@ QgsLayerTreeLayer::QgsLayerTreeLayer( const QgsLayerTreeLayer& other )
attachToLayer();
}

QgsLayerTreeLayer *QgsLayerTreeLayer::createLayerFromSource( const QString &source )
QgsLayerTreeLayer *QgsLayerTreeLayer::createLayerFromParams( const LayerMatchParams &source )
{
QgsLayerTreeLayer* l = new QgsLayerTreeLayer( QString() );
l->attachToSource( source );
Expand Down Expand Up @@ -78,6 +81,35 @@ void QgsLayerTreeLayer::attachToLayer()
}
}

bool QgsLayerTreeLayer::layerMatchesSource( QgsMapLayer* layer, const QgsLayerTreeLayer::LayerMatchParams &params ) const
{
if ( layer->publicSource() != params.source ||
layer->name() != params.name )
return false;

switch ( layer->type() )
{
case QgsMapLayer::VectorLayer:
{
QgsVectorLayer* vl = qobject_cast< QgsVectorLayer* >( layer );
if ( vl->dataProvider()->name() != params.providerKey )
return false;
break;
}
case QgsMapLayer::RasterLayer:
{
QgsRasterLayer* rl = qobject_cast< QgsRasterLayer* >( layer );
if ( rl->dataProvider()->name() != params.providerKey )
return false;
break;
}
case QgsMapLayer::PluginLayer:
break;

}
return true;
}

QString QgsLayerTreeLayer::name() const
{
return layerName();
Expand All @@ -88,13 +120,13 @@ void QgsLayerTreeLayer::setName( const QString& n )
setLayerName( n );
}

void QgsLayerTreeLayer::attachToSource( const QString &source )
void QgsLayerTreeLayer::attachToSource( const LayerMatchParams &source )
{
// check if matching source already open
bool foundMatch = false;
Q_FOREACH ( QgsMapLayer* layer, QgsMapLayerRegistry::instance()->mapLayers() )
{
if ( layer->publicSource() == source )
if ( layerMatchesSource( layer, source ) )
{
// found a source! need to disconnect from layersAdded signal as original attachToLayer call
// will have set this up
Expand All @@ -108,7 +140,7 @@ void QgsLayerTreeLayer::attachToSource( const QString &source )
}

if ( !foundMatch )
mLayerSource = source; // no need to store source if match already made
mLooseMatchParams = source; // no need to store source if match already made
}

QString QgsLayerTreeLayer::layerName() const
Expand Down Expand Up @@ -150,7 +182,10 @@ QgsLayerTreeLayer* QgsLayerTreeLayer::readXML( QDomElement& element , bool loose

QString layerID = element.attribute( "id" );
QString layerName = element.attribute( "name" );

QString source = element.attribute( "source" );
QString providerKey = element.attribute( "providerKey" );

Qt::CheckState checked = QgsLayerTreeUtils::checkStateFromXml( element.attribute( "checked" ) );
bool isExpanded = ( element.attribute( "expanded", "1" ) == "1" );

Expand All @@ -162,7 +197,11 @@ QgsLayerTreeLayer* QgsLayerTreeLayer::readXML( QDomElement& element , bool loose
nodeLayer = new QgsLayerTreeLayer( layer );
else if ( looseMatch && !source.isEmpty() )
{
nodeLayer = QgsLayerTreeLayer::createLayerFromSource( source );
LayerMatchParams params;
params.name = layerName;
params.source = source;
params.providerKey = providerKey;
nodeLayer = QgsLayerTreeLayer::createLayerFromParams( params );
}
else
nodeLayer = new QgsLayerTreeLayer( layerID, layerName );
Expand All @@ -180,8 +219,30 @@ void QgsLayerTreeLayer::writeXML( QDomElement& parentElement )
QDomElement elem = doc.createElement( "layer-tree-layer" );
elem.setAttribute( "id", mLayerId );
if ( mLayer )
{
elem.setAttribute( "source", mLayer->publicSource() );

QString providerKey;
switch ( mLayer->type() )
{
case QgsMapLayer::VectorLayer:
{
QgsVectorLayer* vl = qobject_cast< QgsVectorLayer* >( mLayer );
providerKey = vl->dataProvider()->name();
break;
}
case QgsMapLayer::RasterLayer:
{
QgsRasterLayer* rl = qobject_cast< QgsRasterLayer* >( mLayer );
providerKey = rl->dataProvider()->name();
break;
}
case QgsMapLayer::PluginLayer:
break;
}
elem.setAttribute( "providerKey", providerKey );
}

elem.setAttribute( "name", layerName() );
elem.setAttribute( "checked", QgsLayerTreeUtils::checkStateToXml( mVisible ) );
elem.setAttribute( "expanded", mExpanded ? "1" : "0" );
Expand All @@ -205,7 +266,7 @@ void QgsLayerTreeLayer::registryLayersAdded( const QList<QgsMapLayer*>& layers )
{
Q_FOREACH ( QgsMapLayer* l, layers )
{
if ( !mLayerSource.isEmpty() && l->publicSource() == mLayerSource )
if ( !mLooseMatchParams.source.isEmpty() && layerMatchesSource( l, mLooseMatchParams ) )
{
// we are loosely matching, and found a layer with a matching source.
// Attach to this!
Expand Down
32 changes: 25 additions & 7 deletions src/core/layertree/qgslayertreelayer.h
Expand Up @@ -42,16 +42,28 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode
{
Q_OBJECT
public:

//! Parameters for loose layer matching
struct LayerMatchParams
{
//! Layer public source
QString source;
//! Layer name
QString name;
//! Provider
QString providerKey;
};

explicit QgsLayerTreeLayer( QgsMapLayer* layer );
QgsLayerTreeLayer( const QgsLayerTreeLayer& other );

/**
* Creates a layer node which will attach to a layer with a matching
* QgsMapLayer::publicSource(). This can be used for "looser" layer matching,
* Creates a layer node which will attach to a layer with matching
* parameters. This can be used for "looser" layer matching,
* avoiding the usual layer id check in favour of attaching to any layer
* with an equal source.
* with an equal source/name/provider.
*/
static QgsLayerTreeLayer* createLayerFromSource( const QString& source );
static QgsLayerTreeLayer* createLayerFromParams( const LayerMatchParams& source );

explicit QgsLayerTreeLayer( const QString& layerId, const QString& name = QString() );

Expand All @@ -72,7 +84,7 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode
* avoiding the usual layer id check in favour of attaching to any layer
* with an equal source.
*/
void attachToSource( const QString& source );
void attachToSource( const LayerMatchParams &source );

QString layerName() const;
void setLayerName( const QString& n );
Expand Down Expand Up @@ -112,11 +124,17 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode

QString mLayerId;
QString mLayerName; // only used if layer does not exist

//! Only used when loosely matching to layers - eg when creating a composer legend from template
//! If set this will attach to the first matching layer with an equal source
QString mLayerSource;
//! If set this will attach to the first matching layer with equal parameters
LayerMatchParams mLooseMatchParams;

QgsMapLayer* mLayer; // not owned! may be null
Qt::CheckState mVisible;

private:

bool layerMatchesSource( QgsMapLayer *layer, const LayerMatchParams& params ) const;
};


Expand Down

0 comments on commit 95c3072

Please sign in to comment.