Skip to content

Commit

Permalink
Propagate layer/group name changes in the layer tree (fixes #15844)
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Nov 14, 2016
1 parent 7299e6b commit 968e02d
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 3 deletions.
10 changes: 10 additions & 0 deletions python/core/layertree/qgslayertreelayer.sip
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ class QgsLayerTreeLayer : QgsLayerTreeNode

QgsMapLayer* layer() const;

//! Get layer's name
//! @note added in 3.0
QString name() const;
//! Set layer's name
//! @note added in 3.0
void setName( const QString& n );

QString layerName() const;
void setLayerName( const QString& n );

Expand All @@ -47,6 +54,9 @@ class QgsLayerTreeLayer : QgsLayerTreeNode
protected slots:
void registryLayersAdded( const QList<QgsMapLayer*>& layers );
void registryLayersWillBeRemoved( const QStringList& layerIds );
//! Emits a nameChanged() signal if layer's name has changed
//! @note added in 3.0
void layerNameChanged();

signals:
//! emitted when a previously unavailable layer got loaded
Expand Down
10 changes: 10 additions & 0 deletions python/core/layertree/qgslayertreenode.sip
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ class QgsLayerTreeNode : QObject
//! Get list of children of the node. Children are owned by the parent
QList<QgsLayerTreeNode*> children();

//! Return name of the node
//! @note added in 3.0
virtual QString name() const = 0;
//! Set name of the node. Emits nameChanged signal.
//! @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/;
//! Write layer tree to XML
Expand Down Expand Up @@ -119,6 +126,9 @@ class QgsLayerTreeNode : QObject
void customPropertyChanged( QgsLayerTreeNode *node, const QString& key );
//! Emitted when the collapsed/expanded state of a node within the tree has been changed
void expandedChanged( QgsLayerTreeNode *node, bool expanded );
//! Emitted when the name of the node is changed
//! @note added in 3.0
void nameChanged( QgsLayerTreeNode* node, QString name );

protected:

Expand Down
14 changes: 14 additions & 0 deletions src/core/layertree/qgslayertreegroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ QgsLayerTreeGroup::QgsLayerTreeGroup( const QgsLayerTreeGroup& other )
connect( this, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
}

QString QgsLayerTreeGroup::name() const
{
return mName;
}

void QgsLayerTreeGroup::setName( const QString& n )
{
if ( mName == n )
return;

mName = n;
emit nameChanged( this, n );
}


QgsLayerTreeGroup* QgsLayerTreeGroup::insertGroup( int index, const QString& name )
{
Expand Down
4 changes: 2 additions & 2 deletions src/core/layertree/qgslayertreegroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
QgsLayerTreeGroup( const QgsLayerTreeGroup& other );

//! Get group's name
QString name() const { return mName; }
QString name() const override;
//! Set group's name
void setName( const QString& n ) { mName = n; }
void setName( const QString& n ) override;

//! Insert a new group node with given name at specified position. Newly created node is owned by this group.
QgsLayerTreeGroup* insertGroup( int index, const QString& name );
Expand Down
26 changes: 26 additions & 0 deletions src/core/layertree/qgslayertreelayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ void QgsLayerTreeLayer::attachToLayer()
{
mLayer = l;
mLayerName = l->name();
connect( l, SIGNAL( nameChanged() ), this, SLOT( layerNameChanged() ) );
// make sure we are notified if the layer is removed
connect( QgsMapLayerRegistry::instance(), SIGNAL( layersWillBeRemoved( QStringList ) ), this, SLOT( registryLayersWillBeRemoved( QStringList ) ) );
}
Expand All @@ -70,6 +71,15 @@ void QgsLayerTreeLayer::attachToLayer()
}
}

QString QgsLayerTreeLayer::name() const
{
return layerName();
}

void QgsLayerTreeLayer::setName( const QString& n )
{
setLayerName( n );
}

QString QgsLayerTreeLayer::layerName() const
{
Expand All @@ -79,9 +89,19 @@ QString QgsLayerTreeLayer::layerName() const
void QgsLayerTreeLayer::setLayerName( const QString& n )
{
if ( mLayer )
{
if ( mLayer->name() == n )
return;
mLayer->setName( n );
// no need to emit signal: we will be notified from layer's nameChanged() signal
}
else
{
if ( mLayerName == n )
return;
mLayerName = n;
emit nameChanged( this, n );
}
}

void QgsLayerTreeLayer::setVisible( Qt::CheckState state )
Expand Down Expand Up @@ -170,3 +190,9 @@ void QgsLayerTreeLayer::registryLayersWillBeRemoved( const QStringList& layerIds
mLayer = nullptr;
}
}

void QgsLayerTreeLayer::layerNameChanged()
{
Q_ASSERT( mLayer );
emit nameChanged( this, mLayer->name() );
}
10 changes: 10 additions & 0 deletions src/core/layertree/qgslayertreelayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode

QgsMapLayer* layer() const { return mLayer; }

//! Get layer's name
//! @note added in 3.0
QString name() const override;
//! Set layer's name
//! @note added in 3.0
void setName( const QString& n ) override;

QString layerName() const;
void setLayerName( const QString& n );

Expand All @@ -67,6 +74,9 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode
protected slots:
void registryLayersAdded( const QList<QgsMapLayer*>& layers );
void registryLayersWillBeRemoved( const QStringList& layerIds );
//! Emits a nameChanged() signal if layer's name has changed
//! @note added in 3.0
void layerNameChanged();

signals:
//! emitted when a previously unavailable layer got loaded
Expand Down
11 changes: 10 additions & 1 deletion src/core/layertree/qgslayertreemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,15 @@ void QgsLayerTreeModel::nodeVisibilityChanged( QgsLayerTreeNode* node )
emit dataChanged( index, index );
}

void QgsLayerTreeModel::nodeNameChanged( QgsLayerTreeNode* node, const QString& name )
{
Q_UNUSED( name );
Q_ASSERT( node );

QModelIndex index = node2index( node );
emit dataChanged( index, index );
}


void QgsLayerTreeModel::nodeCustomPropertyChanged( QgsLayerTreeNode* node, const QString& key )
{
Expand Down Expand Up @@ -854,7 +863,6 @@ void QgsLayerTreeModel::connectToLayer( QgsLayerTreeLayer* nodeLayer )
connect( layer, SIGNAL( editingStarted() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
connect( layer, SIGNAL( editingStopped() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
connect( layer, SIGNAL( layerModified() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
connect( layer, SIGNAL( nameChanged() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
}
}

Expand Down Expand Up @@ -927,6 +935,7 @@ void QgsLayerTreeModel::connectToRootNode()
connect( mRootNode, SIGNAL( willRemoveChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillRemoveChildren( QgsLayerTreeNode*, int, int ) ) );
connect( mRootNode, SIGNAL( removedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeRemovedChildren() ) );
connect( mRootNode, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
connect( mRootNode, SIGNAL( nameChanged( QgsLayerTreeNode*, QString ) ), this, SLOT( nodeNameChanged( QgsLayerTreeNode*, QString ) ) );

connect( mRootNode, SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ), this, SLOT( nodeCustomPropertyChanged( QgsLayerTreeNode*, QString ) ) );

Expand Down
1 change: 1 addition & 0 deletions src/core/layertree/qgslayertreemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
void nodeRemovedChildren();

void nodeVisibilityChanged( QgsLayerTreeNode* node );
void nodeNameChanged( QgsLayerTreeNode* node, const QString& name );

This comment has been minimized.

Copy link
@3nids

3nids Nov 14, 2016

Member

missing docs makes PyQgsDocCoverage fail....


void nodeCustomPropertyChanged( QgsLayerTreeNode* node, const QString& key );

Expand Down
1 change: 1 addition & 0 deletions src/core/layertree/qgslayertreenode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ void QgsLayerTreeNode::insertChildrenPrivate( int index, QList<QgsLayerTreeNode*
connect( nodes[i], SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ), this, SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ) );
connect( nodes[i], SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ) );
connect( nodes[i], SIGNAL( expandedChanged( QgsLayerTreeNode*, bool ) ), this, SIGNAL( expandedChanged( QgsLayerTreeNode*, bool ) ) );
connect( nodes[i], SIGNAL( nameChanged( QgsLayerTreeNode*, QString ) ), this, SIGNAL( nameChanged( QgsLayerTreeNode*, QString ) ) );
}
emit addedChildren( this, index, indexTo );
}
Expand Down
10 changes: 10 additions & 0 deletions src/core/layertree/qgslayertreenode.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ class CORE_EXPORT QgsLayerTreeNode : public QObject
//! Get list of children of the node. Children are owned by the parent
QList<QgsLayerTreeNode*> children() { return mChildren; }

//! Return name of the node
//! @note added in 3.0
virtual QString name() const = 0;
//! Set name of the node. Emits nameChanged signal.
//! @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 );
//! Write layer tree to XML
Expand Down Expand Up @@ -126,6 +133,9 @@ class CORE_EXPORT QgsLayerTreeNode : public QObject
void customPropertyChanged( QgsLayerTreeNode *node, const QString& key );
//! Emitted when the collapsed/expanded state of a node within the tree has been changed
void expandedChanged( QgsLayerTreeNode *node, bool expanded );
//! Emitted when the name of the node is changed
//! @note added in 3.0
void nameChanged( QgsLayerTreeNode* node, QString name );

protected:

Expand Down
62 changes: 62 additions & 0 deletions tests/src/core/testqgslayertree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class TestQgsLayerTree : public QObject
private slots:
void initTestCase();
void cleanupTestCase();
void testGroupNameChanged();
void testLayerNameChanged();
void testCheckStateParentToChild();
void testCheckStateChildToParent();
void testCheckStateMutuallyExclusive();
Expand Down Expand Up @@ -80,6 +82,66 @@ void TestQgsLayerTree::cleanupTestCase()
QgsApplication::exitQgis();
}

void TestQgsLayerTree::testGroupNameChanged()
{
QgsLayerTreeNode* secondGroup = mRoot->children()[1];

QSignalSpy spy( mRoot, SIGNAL( nameChanged( QgsLayerTreeNode*, QString ) ) );
secondGroup->setName( "grp2+" );

QCOMPARE( secondGroup->name(), QString( "grp2+" ) );

QCOMPARE( spy.count(), 1 );
QList<QVariant> arguments = spy.takeFirst();
QCOMPARE( arguments.at( 0 ).value<QgsLayerTreeNode*>(), secondGroup );
QCOMPARE( arguments.at( 1 ).toString(), QString( "grp2+" ) );

secondGroup->setName( "grp2" );
QCOMPARE( secondGroup->name(), QString( "grp2" ) );
}

void TestQgsLayerTree::testLayerNameChanged()
{
QgsVectorLayer* vl = new QgsVectorLayer( QStringLiteral( "Point?field=col1:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
QVERIFY( vl->isValid() );

QgsLayerTreeLayer* n = new QgsLayerTreeLayer( vl->id(), vl->name() );
mRoot->addChildNode( n );

QSignalSpy spy( mRoot, SIGNAL( nameChanged( QgsLayerTreeNode*, QString ) ) );

QCOMPARE( n->name(), QString( "vl" ) );
n->setName( "changed 1" );

QCOMPARE( n->name(), QString( "changed 1" ) );
QCOMPARE( spy.count(), 1 );
QList<QVariant> arguments = spy.takeFirst();
QCOMPARE( arguments.at( 0 ).value<QgsLayerTreeNode*>(), n );
QCOMPARE( arguments.at( 1 ).toString(), QString( "changed 1" ) );

QgsMapLayerRegistry::instance()->addMapLayers( QList<QgsMapLayer*>() << vl );

// set name via map layer
vl->setName( "changed 2" );
QCOMPARE( n->name(), QString( "changed 2" ) );
QCOMPARE( spy.count(), 1 );
arguments = spy.takeFirst();
QCOMPARE( arguments.at( 0 ).value<QgsLayerTreeNode*>(), n );
QCOMPARE( arguments.at( 1 ).toString(), QString( "changed 2" ) );

// set name via layer tree
n->setName( "changed 3" );
QCOMPARE( n->name(), QString( "changed 3" ) );
QCOMPARE( spy.count(), 1 );
arguments = spy.takeFirst();
QCOMPARE( arguments.at( 0 ).value<QgsLayerTreeNode*>(), n );
QCOMPARE( arguments.at( 1 ).toString(), QString( "changed 3" ) );

QgsMapLayerRegistry::instance()->removeMapLayers( QList<QgsMapLayer*>() << vl );

mRoot->removeChildNode( n );
}

void TestQgsLayerTree::testCheckStateParentToChild()
{
mRoot->setVisible( Qt::Unchecked );
Expand Down

0 comments on commit 968e02d

Please sign in to comment.