Propagate layer/group name changes in the layer tree (fixes #15844)

This commit is contained in:
Martin Dobias 2016-11-14 19:53:18 +08:00
parent 7299e6b8ba
commit 968e02d6fe
11 changed files with 156 additions and 3 deletions

View File

@ -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 );
@ -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

View File

@ -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
@ -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:

View File

@ -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 )
{

View File

@ -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 );

View File

@ -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 ) ) );
}
@ -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
{
@ -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 )
@ -170,3 +190,9 @@ void QgsLayerTreeLayer::registryLayersWillBeRemoved( const QStringList& layerIds
mLayer = nullptr;
}
}
void QgsLayerTreeLayer::layerNameChanged()
{
Q_ASSERT( mLayer );
emit nameChanged( this, mLayer->name() );
}

View File

@ -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 );
@ -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

View File

@ -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 )
{
@ -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 );
}
}
@ -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 ) ) );

View File

@ -216,6 +216,7 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
void nodeRemovedChildren();
void nodeVisibilityChanged( QgsLayerTreeNode* node );
void nodeNameChanged( QgsLayerTreeNode* node, const QString& name );
void nodeCustomPropertyChanged( QgsLayerTreeNode* node, const QString& key );

View File

@ -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 );
}

View File

@ -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
@ -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:

View File

@ -35,6 +35,8 @@ class TestQgsLayerTree : public QObject
private slots:
void initTestCase();
void cleanupTestCase();
void testGroupNameChanged();
void testLayerNameChanged();
void testCheckStateParentToChild();
void testCheckStateChildToParent();
void testCheckStateMutuallyExclusive();
@ -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 );