Skip to content
Permalink
Browse files

Merge pull request #39872 from elpaso/hidden-layers-bugfix

Hidden layers bugfix
  • Loading branch information
elpaso committed Nov 13, 2020
2 parents 3f11294 + cb43bd8 commit 8c06a1ac43983b3d9b3a75246d3d68dc22be834e
@@ -203,6 +203,7 @@ of -1 will determine automatically (either first one currently checked or none)
%End

protected slots:

void nodeVisibilityChanged( QgsLayerTreeNode *node );

protected:
@@ -216,6 +217,7 @@ Set check state of children - if mutually exclusive




private:

QgsLayerTreeGroup( const QgsLayerTreeGroup &other );
@@ -98,6 +98,7 @@ Gets pointer to the parent. If parent is ``None``, the node is a root node
Gets list of children of the node. Children are owned by the parent
%End


virtual QString name() const = 0;
%Docstring
Returns name of the node
@@ -316,6 +317,7 @@ Low-level removal of children from the node.

protected:


};


@@ -204,7 +204,10 @@ void QgsProjectLayerGroupDialog::changeProjectFile()
QDomElement layerTreeElem = projectDom.documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
if ( !layerTreeElem.isNull() )
{
mRootGroup->readChildrenFromXml( layerTreeElem, QgsReadWriteContext() );
// Use a temporary tree to read the nodes to prevent signals being delivered to the models
QgsLayerTree tempTree;
tempTree.readChildrenFromXml( layerTreeElem, QgsReadWriteContext() );
mRootGroup->insertChildNodes( -1, tempTree.abandonChildren() );
}
else
{
@@ -328,6 +328,11 @@ Qt::ItemFlags QgsSnappingLayerTreeModel::flags( const QModelIndex &idx ) const

QModelIndex QgsSnappingLayerTreeModel::index( int row, int column, const QModelIndex &parent ) const
{
if ( row < 0 || column < 0 || row >= rowCount( parent ) || column >= columnCount( parent ) )
{
return QModelIndex();
}

QModelIndex newIndex = QSortFilterProxyModel::index( row, LayerColumn, parent );
if ( column == LayerColumn )
return newIndex;
@@ -43,6 +43,9 @@
#include "qgssettings.h"
#include "qgsscalewidget.h"

#ifdef ENABLE_MODELTEST
#include "modeltest.h"
#endif

class SnapTypeMenu: public QMenu
{
@@ -88,6 +91,12 @@ QgsSnappingWidget::QgsSnappingWidget( QgsProject *project, QgsMapCanvas *canvas,
mLayerTreeView = new QTreeView();
QgsSnappingLayerTreeModel *model = new QgsSnappingLayerTreeModel( mProject, mCanvas, this );
model->setLayerTreeModel( new QgsLayerTreeModel( mProject->layerTreeRoot(), model ) );

#ifdef ENABLE_MODELTEST
new ModelTest( model, this );
new ModelTest( model->layerTreeModel(), this );
#endif

// connections
connect( model, &QgsSnappingLayerTreeModel::rowsInserted, this, &QgsSnappingWidget::onSnappingTreeLayersChanged );
connect( model, &QgsSnappingLayerTreeModel::modelReset, this, &QgsSnappingWidget::onSnappingTreeLayersChanged );
@@ -442,6 +442,13 @@ void QgsLayerTreeGroup::updateChildVisibilityMutuallyExclusive()
mChangingChildVisibility = false;
}

void QgsLayerTreeGroup::makeOrphan()
{
QgsLayerTreeNode::makeOrphan();
// Reconnect internal signals
connect( this, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeGroup::nodeVisibilityChanged );
}

void QgsLayerTreeGroup::setItemVisibilityCheckedRecursive( bool checked )
{
QgsLayerTreeNode::setItemVisibilityChecked( checked );
@@ -206,6 +206,7 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
void setIsMutuallyExclusive( bool enabled, int initialChildIndex = -1 );

protected slots:

void nodeVisibilityChanged( QgsLayerTreeNode *node );

protected:
@@ -228,6 +229,9 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
*/
int mMutuallyExclusiveChildIndex = -1;

//! Sets parent to NULLPTR and disconnects all external and forwarded signals
virtual void makeOrphan() override SIP_SKIP;

private:

#ifdef SIP_RUN
@@ -240,6 +244,7 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode

QgsLayerTreeGroup &operator= ( const QgsLayerTreeGroup & ) = delete;


};


@@ -723,7 +723,6 @@ int QgsLayerTreeModel::scaleIconSize( int standardSize )

void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
{
Q_ASSERT( node );
beginInsertRows( node2index( node ), indexFrom, indexTo );
}

@@ -774,7 +773,7 @@ void QgsLayerTreeModel::nodeVisibilityChanged( QgsLayerTreeNode *node )
{
Q_ASSERT( node );

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

@@ -783,7 +782,7 @@ void QgsLayerTreeModel::nodeNameChanged( QgsLayerTreeNode *node, const QString &
Q_UNUSED( name )
Q_ASSERT( node );

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

@@ -900,12 +899,12 @@ void QgsLayerTreeModel::connectToLayer( QgsLayerTreeLayer *nodeLayer )
{
// in order to connect to layer, we need to have it loaded.
// keep an eye on the layer ID: once loaded, we will use it
connect( nodeLayer, &QgsLayerTreeLayer::layerLoaded, this, &QgsLayerTreeModel::nodeLayerLoaded );
connect( nodeLayer, &QgsLayerTreeLayer::layerLoaded, this, &QgsLayerTreeModel::nodeLayerLoaded, Qt::UniqueConnection );
return;
}

// watch if the layer is getting removed
connect( nodeLayer, &QgsLayerTreeLayer::layerWillBeUnloaded, this, &QgsLayerTreeModel::nodeLayerWillBeUnloaded );
connect( nodeLayer, &QgsLayerTreeLayer::layerWillBeUnloaded, this, &QgsLayerTreeModel::nodeLayerWillBeUnloaded, Qt::UniqueConnection );

if ( testFlag( ShowLegend ) )
{
@@ -1004,14 +1003,13 @@ void QgsLayerTreeModel::connectToRootNode()
{
Q_ASSERT( mRootNode );

connect( mRootNode, &QgsLayerTreeNode::willAddChildren, this, &QgsLayerTreeModel::nodeWillAddChildren );
connect( mRootNode, &QgsLayerTreeNode::addedChildren, this, &QgsLayerTreeModel::nodeAddedChildren );
connect( mRootNode, &QgsLayerTreeNode::willRemoveChildren, this, &QgsLayerTreeModel::nodeWillRemoveChildren );
connect( mRootNode, &QgsLayerTreeNode::removedChildren, this, &QgsLayerTreeModel::nodeRemovedChildren );
connect( mRootNode, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeModel::nodeVisibilityChanged );
connect( mRootNode, &QgsLayerTreeNode::nameChanged, this, &QgsLayerTreeModel::nodeNameChanged );

connect( mRootNode, &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayerTreeModel::nodeCustomPropertyChanged );
connect( mRootNode, &QgsLayerTreeNode::willAddChildren, this, &QgsLayerTreeModel::nodeWillAddChildren, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::addedChildren, this, &QgsLayerTreeModel::nodeAddedChildren, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::willRemoveChildren, this, &QgsLayerTreeModel::nodeWillRemoveChildren, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::removedChildren, this, &QgsLayerTreeModel::nodeRemovedChildren, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeModel::nodeVisibilityChanged, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::nameChanged, this, &QgsLayerTreeModel::nodeNameChanged, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayerTreeModel::nodeCustomPropertyChanged, Qt::ConnectionType::UniqueConnection );

connectToLayers( mRootNode );
}
@@ -1365,7 +1363,17 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer *nodeL )
int count = legendTree ? legendTree->children[nullptr].count() : filteredLstNew.count();

if ( !filteredLstNew.isEmpty() )
{
// Make sure it's clear
const QModelIndex nodeIndex { node2index( nodeL ) };
if ( rowCount( nodeIndex ) > 0 )
{
beginRemoveRows( node2index( nodeL ), 0, rowCount( nodeIndex ) - 1 );
mLegend[nodeL] = LayerLegendData();
endRemoveRows();
}
beginInsertRows( node2index( nodeL ), 0, count - 1 );
}

LayerLegendData data;
data.originalNodes = lstNew;
@@ -1376,7 +1384,9 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer *nodeL )
mLegend[nodeL] = data;

if ( !filteredLstNew.isEmpty() )
{
endInsertRows();
}

// invalidate map based data even if the data is not map-based to make sure
// the symbol sizes are computed at least once
@@ -471,6 +471,7 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel

//! Returns a temporary render context
QgsRenderContext *createTemporaryRenderContext() const;

};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsLayerTreeModel::Flags )
@@ -48,6 +48,23 @@ QgsLayerTreeNode::~QgsLayerTreeNode()
qDeleteAll( mChildren );
}

QList<QgsLayerTreeNode *> QgsLayerTreeNode::abandonChildren()
{
const QList<QgsLayerTreeNode *> orphans { mChildren };
mChildren.clear();
for ( auto orphan : qgis::as_const( orphans ) )
{
orphan->makeOrphan( );
}
return orphans;
}

void QgsLayerTreeNode::makeOrphan()
{
disconnect();
mParent = nullptr;
}

QgsLayerTreeNode *QgsLayerTreeNode::readXml( QDomElement &element, const QgsReadWriteContext &context )
{
QgsLayerTreeNode *node = nullptr;
@@ -231,12 +248,15 @@ void QgsLayerTreeNode::insertChildrenPrivate( int index, QList<QgsLayerTreeNode
if ( index < 0 || index >= mChildren.count() )
index = mChildren.count();

int indexTo = index + nodes.count() - 1;
emit willAddChildren( this, index, indexTo );
for ( int i = 0; i < nodes.count(); ++i )
{
QgsLayerTreeNode *node = nodes.at( i );

const QList<QgsLayerTreeNode *> orphans { node->abandonChildren() };

emit willAddChildren( this, index + i, index + i );
mChildren.insert( index + i, node );
emit addedChildren( this, index + i, index + i );

// forward the signal towards the root
connect( node, &QgsLayerTreeNode::willAddChildren, this, &QgsLayerTreeNode::willAddChildren );
@@ -247,27 +267,50 @@ void QgsLayerTreeNode::insertChildrenPrivate( int index, QList<QgsLayerTreeNode
connect( node, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeNode::visibilityChanged );
connect( node, &QgsLayerTreeNode::expandedChanged, this, &QgsLayerTreeNode::expandedChanged );
connect( node, &QgsLayerTreeNode::nameChanged, this, &QgsLayerTreeNode::nameChanged );

// Now add children
if ( ! orphans.isEmpty() )
{
node->insertChildrenPrivate( -1, orphans );
}

}
emit addedChildren( this, index, indexTo );
}

void QgsLayerTreeNode::removeChildrenPrivate( int from, int count, bool destroy )
{
if ( from < 0 || count <= 0 )
return;

int to = from + count - 1;
const int to = from + count - 1;
if ( to >= mChildren.count() )
return;
emit willRemoveChildren( this, from, to );

// Remove in reverse order
while ( --count >= 0 )
{
QgsLayerTreeNode *node = mChildren.takeAt( from );
node->mParent = nullptr;
const int last { from + count };
Q_ASSERT( last >= 0 && last < mChildren.count( ) );
QgsLayerTreeNode *node = mChildren.at( last );

// Remove children first
if ( ! node->children().isEmpty() )
{
node->removeChildrenPrivate( 0, node->children().count( ), destroy );
}

emit willRemoveChildren( this, last, last );
node = mChildren.takeAt( last );
if ( destroy )
{
delete node;
}
else
{
node->makeOrphan();
}
emit removedChildren( this, last, last );
}
emit removedChildren( this, from, to );
}

bool QgsLayerTreeNode::takeChild( QgsLayerTreeNode *node )
@@ -113,6 +113,13 @@ class CORE_EXPORT QgsLayerTreeNode : public QObject
//! Gets list of children of the node. Children are owned by the parent
QList<QgsLayerTreeNode *> children() const { return mChildren; } SIP_SKIP

/**
* Removes the childrens, disconnect all the forwarded and external signals and sets their parent to NULLPTR
* \return the removed children
* \since QGIS 3.16
*/
QList<QgsLayerTreeNode *> abandonChildren() SIP_SKIP;

/**
* Returns name of the node
* \since QGIS 3.0
@@ -286,8 +293,12 @@ class CORE_EXPORT QgsLayerTreeNode : public QObject
//! custom properties attached to the node
QgsObjectCustomProperties mProperties;

//! Sets parent to NULLPTR and disconnects all external and forwarded signals
virtual void makeOrphan() SIP_SKIP;

private:
QgsLayerTreeNode &operator=( const QgsLayerTreeNode & ) = delete;

};


@@ -30,7 +30,7 @@ QgsLayerTreeRegistryBridge::QgsLayerTreeRegistryBridge( QgsLayerTreeGroup *root,
, mInsertionPoint( root, 0 )
{
connect( mProject, &QgsProject::legendLayersAdded, this, &QgsLayerTreeRegistryBridge::layersAdded );
connect( mProject, static_cast < void ( QgsProject::* )( const QStringList & ) >( &QgsProject::layersWillBeRemoved ), this, &QgsLayerTreeRegistryBridge::layersWillBeRemoved );
connect( mProject, qgis::overload<const QStringList &>::of<QgsProject>( &QgsProject::layersWillBeRemoved ), this, &QgsLayerTreeRegistryBridge::layersWillBeRemoved );

connect( mRoot, &QgsLayerTreeNode::willRemoveChildren, this, &QgsLayerTreeRegistryBridge::groupWillRemoveChildren );
connect( mRoot, &QgsLayerTreeNode::removedChildren, this, &QgsLayerTreeRegistryBridge::groupRemovedChildren );
@@ -118,7 +118,7 @@ static void _collectLayerIdsInGroup( QgsLayerTreeGroup *group, int indexFrom, in

void QgsLayerTreeRegistryBridge::groupWillRemoveChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
{
if ( mRegistryRemovingLayers )
if ( mRegistryRemovingLayers || QgsLayerTree::isGroup( node ) )
return; // do not try to remove those layers again

Q_ASSERT( mLayerIdsForRemoval.isEmpty() );
@@ -186,9 +186,7 @@ bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsProject *proj
root->resolveReferences( project );

QList<QgsLayerTreeNode *> nodes = root->children();
const auto constNodes = nodes;
for ( QgsLayerTreeNode *node : constNodes )
root->takeChild( node );
root->abandonChildren();
delete root;

rootGroup->insertChildNodes( -1, nodes );
@@ -1536,7 +1536,10 @@ bool QgsProject::readProjectFile( const QString &filename, QgsProject::ReadFlags
QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
if ( !layerTreeElem.isNull() )
{
mRootGroup->readChildrenFromXml( layerTreeElem, context );
// Use a temporary tree to read the nodes to prevent signals being delivered to the models
QgsLayerTree tempTree;
tempTree.readChildrenFromXml( layerTreeElem, context );
mRootGroup->insertChildNodes( -1, tempTree.abandonChildren() );
}
else
{

0 comments on commit 8c06a1a

Please sign in to comment.
You can’t perform that action at this time.