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

Hidden layers bugfix
This commit is contained in:
Alessandro Pasotti 2020-11-13 10:40:14 +01:00 committed by GitHub
commit 8c06a1ac43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 195 additions and 43 deletions

View File

@ -203,6 +203,7 @@ of -1 will determine automatically (either first one currently checked or none)
%End %End
protected slots: protected slots:
void nodeVisibilityChanged( QgsLayerTreeNode *node ); void nodeVisibilityChanged( QgsLayerTreeNode *node );
protected: protected:
@ -216,6 +217,7 @@ Set check state of children - if mutually exclusive
private: private:
QgsLayerTreeGroup( const QgsLayerTreeGroup &other ); QgsLayerTreeGroup( const QgsLayerTreeGroup &other );

View File

@ -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 Gets list of children of the node. Children are owned by the parent
%End %End
virtual QString name() const = 0; virtual QString name() const = 0;
%Docstring %Docstring
Returns name of the node Returns name of the node
@ -316,6 +317,7 @@ Low-level removal of children from the node.
protected: protected:
}; };

View File

@ -204,7 +204,10 @@ void QgsProjectLayerGroupDialog::changeProjectFile()
QDomElement layerTreeElem = projectDom.documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) ); QDomElement layerTreeElem = projectDom.documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
if ( !layerTreeElem.isNull() ) 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 else
{ {

View File

@ -328,6 +328,11 @@ Qt::ItemFlags QgsSnappingLayerTreeModel::flags( const QModelIndex &idx ) const
QModelIndex QgsSnappingLayerTreeModel::index( int row, int column, const QModelIndex &parent ) 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 ); QModelIndex newIndex = QSortFilterProxyModel::index( row, LayerColumn, parent );
if ( column == LayerColumn ) if ( column == LayerColumn )
return newIndex; return newIndex;

View File

@ -43,6 +43,9 @@
#include "qgssettings.h" #include "qgssettings.h"
#include "qgsscalewidget.h" #include "qgsscalewidget.h"
#ifdef ENABLE_MODELTEST
#include "modeltest.h"
#endif
class SnapTypeMenu: public QMenu class SnapTypeMenu: public QMenu
{ {
@ -88,6 +91,12 @@ QgsSnappingWidget::QgsSnappingWidget( QgsProject *project, QgsMapCanvas *canvas,
mLayerTreeView = new QTreeView(); mLayerTreeView = new QTreeView();
QgsSnappingLayerTreeModel *model = new QgsSnappingLayerTreeModel( mProject, mCanvas, this ); QgsSnappingLayerTreeModel *model = new QgsSnappingLayerTreeModel( mProject, mCanvas, this );
model->setLayerTreeModel( new QgsLayerTreeModel( mProject->layerTreeRoot(), model ) ); model->setLayerTreeModel( new QgsLayerTreeModel( mProject->layerTreeRoot(), model ) );
#ifdef ENABLE_MODELTEST
new ModelTest( model, this );
new ModelTest( model->layerTreeModel(), this );
#endif
// connections // connections
connect( model, &QgsSnappingLayerTreeModel::rowsInserted, this, &QgsSnappingWidget::onSnappingTreeLayersChanged ); connect( model, &QgsSnappingLayerTreeModel::rowsInserted, this, &QgsSnappingWidget::onSnappingTreeLayersChanged );
connect( model, &QgsSnappingLayerTreeModel::modelReset, this, &QgsSnappingWidget::onSnappingTreeLayersChanged ); connect( model, &QgsSnappingLayerTreeModel::modelReset, this, &QgsSnappingWidget::onSnappingTreeLayersChanged );

View File

@ -442,6 +442,13 @@ void QgsLayerTreeGroup::updateChildVisibilityMutuallyExclusive()
mChangingChildVisibility = false; mChangingChildVisibility = false;
} }
void QgsLayerTreeGroup::makeOrphan()
{
QgsLayerTreeNode::makeOrphan();
// Reconnect internal signals
connect( this, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeGroup::nodeVisibilityChanged );
}
void QgsLayerTreeGroup::setItemVisibilityCheckedRecursive( bool checked ) void QgsLayerTreeGroup::setItemVisibilityCheckedRecursive( bool checked )
{ {
QgsLayerTreeNode::setItemVisibilityChecked( checked ); QgsLayerTreeNode::setItemVisibilityChecked( checked );

View File

@ -206,6 +206,7 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
void setIsMutuallyExclusive( bool enabled, int initialChildIndex = -1 ); void setIsMutuallyExclusive( bool enabled, int initialChildIndex = -1 );
protected slots: protected slots:
void nodeVisibilityChanged( QgsLayerTreeNode *node ); void nodeVisibilityChanged( QgsLayerTreeNode *node );
protected: protected:
@ -228,6 +229,9 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
*/ */
int mMutuallyExclusiveChildIndex = -1; int mMutuallyExclusiveChildIndex = -1;
//! Sets parent to NULLPTR and disconnects all external and forwarded signals
virtual void makeOrphan() override SIP_SKIP;
private: private:
#ifdef SIP_RUN #ifdef SIP_RUN
@ -240,6 +244,7 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
QgsLayerTreeGroup &operator= ( const QgsLayerTreeGroup & ) = delete; QgsLayerTreeGroup &operator= ( const QgsLayerTreeGroup & ) = delete;
}; };

View File

@ -723,7 +723,6 @@ int QgsLayerTreeModel::scaleIconSize( int standardSize )
void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo ) void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
{ {
Q_ASSERT( node );
beginInsertRows( node2index( node ), indexFrom, indexTo ); beginInsertRows( node2index( node ), indexFrom, indexTo );
} }
@ -774,7 +773,7 @@ void QgsLayerTreeModel::nodeVisibilityChanged( QgsLayerTreeNode *node )
{ {
Q_ASSERT( node ); Q_ASSERT( node );
QModelIndex index = node2index( node ); const QModelIndex index = node2index( node );
emit dataChanged( index, index ); emit dataChanged( index, index );
} }
@ -783,7 +782,7 @@ void QgsLayerTreeModel::nodeNameChanged( QgsLayerTreeNode *node, const QString &
Q_UNUSED( name ) Q_UNUSED( name )
Q_ASSERT( node ); Q_ASSERT( node );
QModelIndex index = node2index( node ); const QModelIndex index = node2index( node );
emit dataChanged( index, index ); 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. // 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 // 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; return;
} }
// watch if the layer is getting removed // 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 ) ) if ( testFlag( ShowLegend ) )
{ {
@ -1004,14 +1003,13 @@ void QgsLayerTreeModel::connectToRootNode()
{ {
Q_ASSERT( mRootNode ); Q_ASSERT( mRootNode );
connect( mRootNode, &QgsLayerTreeNode::willAddChildren, this, &QgsLayerTreeModel::nodeWillAddChildren ); connect( mRootNode, &QgsLayerTreeNode::willAddChildren, this, &QgsLayerTreeModel::nodeWillAddChildren, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::addedChildren, this, &QgsLayerTreeModel::nodeAddedChildren ); connect( mRootNode, &QgsLayerTreeNode::addedChildren, this, &QgsLayerTreeModel::nodeAddedChildren, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::willRemoveChildren, this, &QgsLayerTreeModel::nodeWillRemoveChildren ); connect( mRootNode, &QgsLayerTreeNode::willRemoveChildren, this, &QgsLayerTreeModel::nodeWillRemoveChildren, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::removedChildren, this, &QgsLayerTreeModel::nodeRemovedChildren ); connect( mRootNode, &QgsLayerTreeNode::removedChildren, this, &QgsLayerTreeModel::nodeRemovedChildren, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeModel::nodeVisibilityChanged ); connect( mRootNode, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeModel::nodeVisibilityChanged, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::nameChanged, this, &QgsLayerTreeModel::nodeNameChanged ); connect( mRootNode, &QgsLayerTreeNode::nameChanged, this, &QgsLayerTreeModel::nodeNameChanged, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayerTreeModel::nodeCustomPropertyChanged, Qt::ConnectionType::UniqueConnection );
connect( mRootNode, &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayerTreeModel::nodeCustomPropertyChanged );
connectToLayers( mRootNode ); connectToLayers( mRootNode );
} }
@ -1365,7 +1363,17 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer *nodeL )
int count = legendTree ? legendTree->children[nullptr].count() : filteredLstNew.count(); int count = legendTree ? legendTree->children[nullptr].count() : filteredLstNew.count();
if ( !filteredLstNew.isEmpty() ) 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 ); beginInsertRows( node2index( nodeL ), 0, count - 1 );
}
LayerLegendData data; LayerLegendData data;
data.originalNodes = lstNew; data.originalNodes = lstNew;
@ -1376,7 +1384,9 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer *nodeL )
mLegend[nodeL] = data; mLegend[nodeL] = data;
if ( !filteredLstNew.isEmpty() ) if ( !filteredLstNew.isEmpty() )
{
endInsertRows(); endInsertRows();
}
// invalidate map based data even if the data is not map-based to make sure // invalidate map based data even if the data is not map-based to make sure
// the symbol sizes are computed at least once // the symbol sizes are computed at least once

View File

@ -471,6 +471,7 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
//! Returns a temporary render context //! Returns a temporary render context
QgsRenderContext *createTemporaryRenderContext() const; QgsRenderContext *createTemporaryRenderContext() const;
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsLayerTreeModel::Flags ) Q_DECLARE_OPERATORS_FOR_FLAGS( QgsLayerTreeModel::Flags )

View File

@ -48,6 +48,23 @@ QgsLayerTreeNode::~QgsLayerTreeNode()
qDeleteAll( mChildren ); 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 *QgsLayerTreeNode::readXml( QDomElement &element, const QgsReadWriteContext &context )
{ {
QgsLayerTreeNode *node = nullptr; QgsLayerTreeNode *node = nullptr;
@ -231,12 +248,15 @@ void QgsLayerTreeNode::insertChildrenPrivate( int index, QList<QgsLayerTreeNode
if ( index < 0 || index >= mChildren.count() ) if ( index < 0 || index >= mChildren.count() )
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 ) for ( int i = 0; i < nodes.count(); ++i )
{ {
QgsLayerTreeNode *node = nodes.at( i ); QgsLayerTreeNode *node = nodes.at( i );
const QList<QgsLayerTreeNode *> orphans { node->abandonChildren() };
emit willAddChildren( this, index + i, index + i );
mChildren.insert( index + i, node ); mChildren.insert( index + i, node );
emit addedChildren( this, index + i, index + i );
// forward the signal towards the root // forward the signal towards the root
connect( node, &QgsLayerTreeNode::willAddChildren, this, &QgsLayerTreeNode::willAddChildren ); connect( node, &QgsLayerTreeNode::willAddChildren, this, &QgsLayerTreeNode::willAddChildren );
@ -247,8 +267,14 @@ void QgsLayerTreeNode::insertChildrenPrivate( int index, QList<QgsLayerTreeNode
connect( node, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeNode::visibilityChanged ); connect( node, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeNode::visibilityChanged );
connect( node, &QgsLayerTreeNode::expandedChanged, this, &QgsLayerTreeNode::expandedChanged ); connect( node, &QgsLayerTreeNode::expandedChanged, this, &QgsLayerTreeNode::expandedChanged );
connect( node, &QgsLayerTreeNode::nameChanged, this, &QgsLayerTreeNode::nameChanged ); 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 ) void QgsLayerTreeNode::removeChildrenPrivate( int from, int count, bool destroy )
@ -256,18 +282,35 @@ void QgsLayerTreeNode::removeChildrenPrivate( int from, int count, bool destroy
if ( from < 0 || count <= 0 ) if ( from < 0 || count <= 0 )
return; return;
int to = from + count - 1; const int to = from + count - 1;
if ( to >= mChildren.count() ) if ( to >= mChildren.count() )
return; return;
emit willRemoveChildren( this, from, to );
// Remove in reverse order
while ( --count >= 0 ) while ( --count >= 0 )
{ {
QgsLayerTreeNode *node = mChildren.takeAt( from ); const int last { from + count };
node->mParent = nullptr; 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 ) if ( destroy )
{
delete node; delete node;
}
else
{
node->makeOrphan();
}
emit removedChildren( this, last, last );
} }
emit removedChildren( this, from, to );
} }
bool QgsLayerTreeNode::takeChild( QgsLayerTreeNode *node ) bool QgsLayerTreeNode::takeChild( QgsLayerTreeNode *node )

View File

@ -113,6 +113,13 @@ class CORE_EXPORT QgsLayerTreeNode : public QObject
//! Gets list of children of the node. Children are owned by the parent //! Gets list of children of the node. Children are owned by the parent
QList<QgsLayerTreeNode *> children() const { return mChildren; } SIP_SKIP 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 * Returns name of the node
* \since QGIS 3.0 * \since QGIS 3.0
@ -286,8 +293,12 @@ class CORE_EXPORT QgsLayerTreeNode : public QObject
//! custom properties attached to the node //! custom properties attached to the node
QgsObjectCustomProperties mProperties; QgsObjectCustomProperties mProperties;
//! Sets parent to NULLPTR and disconnects all external and forwarded signals
virtual void makeOrphan() SIP_SKIP;
private: private:
QgsLayerTreeNode &operator=( const QgsLayerTreeNode & ) = delete; QgsLayerTreeNode &operator=( const QgsLayerTreeNode & ) = delete;
}; };

View File

@ -30,7 +30,7 @@ QgsLayerTreeRegistryBridge::QgsLayerTreeRegistryBridge( QgsLayerTreeGroup *root,
, mInsertionPoint( root, 0 ) , mInsertionPoint( root, 0 )
{ {
connect( mProject, &QgsProject::legendLayersAdded, this, &QgsLayerTreeRegistryBridge::layersAdded ); 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::willRemoveChildren, this, &QgsLayerTreeRegistryBridge::groupWillRemoveChildren );
connect( mRoot, &QgsLayerTreeNode::removedChildren, this, &QgsLayerTreeRegistryBridge::groupRemovedChildren ); 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 ) 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 return; // do not try to remove those layers again
Q_ASSERT( mLayerIdsForRemoval.isEmpty() ); Q_ASSERT( mLayerIdsForRemoval.isEmpty() );

View File

@ -186,9 +186,7 @@ bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsProject *proj
root->resolveReferences( project ); root->resolveReferences( project );
QList<QgsLayerTreeNode *> nodes = root->children(); QList<QgsLayerTreeNode *> nodes = root->children();
const auto constNodes = nodes; root->abandonChildren();
for ( QgsLayerTreeNode *node : constNodes )
root->takeChild( node );
delete root; delete root;
rootGroup->insertChildNodes( -1, nodes ); rootGroup->insertChildNodes( -1, nodes );

View File

@ -1536,7 +1536,10 @@ bool QgsProject::readProjectFile( const QString &filename, QgsProject::ReadFlags
QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) ); QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
if ( !layerTreeElem.isNull() ) 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 else
{ {

View File

@ -32,6 +32,10 @@
#include <QHeaderView> #include <QHeaderView>
#include <QScrollBar> #include <QScrollBar>
#ifdef ENABLE_MODELTEST
#include "modeltest.h"
#endif
#include "qgslayertreeviewindicator.h" #include "qgslayertreeviewindicator.h"
#include "qgslayertreeviewitemdelegate.h" #include "qgslayertreeviewitemdelegate.h"
@ -85,9 +89,6 @@ void QgsLayerTreeView::setModel( QAbstractItemModel *model )
if ( !treeModel ) if ( !treeModel )
return; return;
connect( treeModel, &QAbstractItemModel::rowsInserted, this, &QgsLayerTreeView::modelRowsInserted );
connect( treeModel, &QAbstractItemModel::rowsRemoved, this, &QgsLayerTreeView::modelRowsRemoved );
if ( mMessageBar ) if ( mMessageBar )
connect( treeModel, &QgsLayerTreeModel::messageEmitted, connect( treeModel, &QgsLayerTreeModel::messageEmitted,
[ = ]( const QString & message, Qgis::MessageLevel level = Qgis::Info, int duration = 5 ) [ = ]( const QString & message, Qgis::MessageLevel level = Qgis::Info, int duration = 5 )
@ -95,6 +96,14 @@ void QgsLayerTreeView::setModel( QAbstractItemModel *model )
); );
mProxyModel = new QgsLayerTreeProxyModel( treeModel, this ); mProxyModel = new QgsLayerTreeProxyModel( treeModel, this );
connect( mProxyModel, &QAbstractItemModel::rowsInserted, this, &QgsLayerTreeView::modelRowsInserted );
connect( mProxyModel, &QAbstractItemModel::rowsRemoved, this, &QgsLayerTreeView::modelRowsRemoved );
#ifdef ENABLE_MODELTEST
new ModelTest( mProxyModel, this );
#endif
mProxyModel->setShowPrivateLayers( mShowPrivateLayers ); mProxyModel->setShowPrivateLayers( mShowPrivateLayers );
QTreeView::setModel( mProxyModel ); QTreeView::setModel( mProxyModel );
@ -108,6 +117,8 @@ void QgsLayerTreeView::setModel( QAbstractItemModel *model )
connect( treeModel, &QAbstractItemModel::dataChanged, this, &QgsLayerTreeView::onDataChanged ); connect( treeModel, &QAbstractItemModel::dataChanged, this, &QgsLayerTreeView::onDataChanged );
updateExpandedStateFromNode( treeModel->rootGroup() ); updateExpandedStateFromNode( treeModel->rootGroup() );
//checkModel();
} }
QgsLayerTreeModel *QgsLayerTreeView::layerTreeModel() const QgsLayerTreeModel *QgsLayerTreeView::layerTreeModel() const
@ -176,7 +187,7 @@ void QgsLayerTreeView::contextMenuEvent( QContextMenuEvent *event )
void QgsLayerTreeView::modelRowsInserted( const QModelIndex &index, int start, int end ) void QgsLayerTreeView::modelRowsInserted( const QModelIndex &index, int start, int end )
{ {
QgsLayerTreeNode *parentNode = layerTreeModel()->index2node( index ); QgsLayerTreeNode *parentNode = index2node( index );
if ( !parentNode ) if ( !parentNode )
return; return;
@ -303,6 +314,8 @@ void QgsLayerTreeView::onCurrentChanged()
layerTreeModel()->setCurrentIndex( mProxyModel->mapToSource( proxyModelNodeLayerIndex ) ); layerTreeModel()->setCurrentIndex( mProxyModel->mapToSource( proxyModelNodeLayerIndex ) );
} }
//checkModel();
emit currentLayerChanged( layerCurrent ); emit currentLayerChanged( layerCurrent );
} }
@ -332,6 +345,7 @@ void QgsLayerTreeView::onCustomPropertyChanged( QgsLayerTreeNode *node, const QS
void QgsLayerTreeView::onModelReset() void QgsLayerTreeView::onModelReset()
{ {
updateExpandedStateFromNode( layerTreeModel()->rootGroup() ); updateExpandedStateFromNode( layerTreeModel()->rootGroup() );
//checkModel();
} }
void QgsLayerTreeView::updateExpandedStateFromNode( QgsLayerTreeNode *node ) void QgsLayerTreeView::updateExpandedStateFromNode( QgsLayerTreeNode *node )
@ -640,8 +654,38 @@ void QgsLayerTreeView::onDataChanged( const QModelIndex &topLeft, const QModelIn
if ( roles.contains( Qt::SizeHintRole ) ) if ( roles.contains( Qt::SizeHintRole ) )
viewport()->update(); viewport()->update();
//checkModel();
} }
#if 0
// for model debugging
void QgsLayerTreeView::checkModel()
{
std::function<void( QgsLayerTreeNode *, int )> debug;
debug = [ & ]( QgsLayerTreeNode * node, int depth )
{
if ( depth == 1 )
qDebug() << "----------------------------------------------";
qDebug() << depth << node->name() << node2index( node ) << layerTreeModel()->rowCount( node2sourceIndex( node ) ) << mProxyModel->rowCount( node2index( node ) );
Q_ASSERT( node == index2node( node2index( node ) ) );
Q_ASSERT( node == layerTreeModel()->index2node( node2sourceIndex( node ) ) );
Q_ASSERT( layerTreeModel()->rowCount( node2sourceIndex( node ) ) == mProxyModel->rowCount( node2index( node ) ) );
for ( int i = 0; i < mProxyModel->rowCount( node2index( node ) ); i++ )
{
QgsLayerTreeNode *childNode { index2node( mProxyModel->index( i, 0, node2index( node ) ) ) };
if ( childNode )
debug( childNode, depth + 1 );
else
qDebug() << "Warning no child node!";
}
};
debug( layerTreeModel()->rootGroup(), 1 );
}
#endif
QgsLayerTreeProxyModel *QgsLayerTreeView::proxyModel() const QgsLayerTreeProxyModel *QgsLayerTreeView::proxyModel() const
{ {
return mProxyModel; return mProxyModel;

View File

@ -80,6 +80,7 @@ class GUI_EXPORT QgsLayerTreeProxyModel : public QSortFilterProxyModel
QgsLayerTreeModel *mLayerTreeModel = nullptr; QgsLayerTreeModel *mLayerTreeModel = nullptr;
QString mFilterText; QString mFilterText;
bool mShowPrivateLayers = false; bool mShowPrivateLayers = false;
}; };
@ -403,6 +404,9 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
bool mShowPrivateLayers = false; bool mShowPrivateLayers = false;
// For model debugging
// void checkModel( );
// friend so it can access viewOptions() method and mLastReleaseMousePos without making them public // friend so it can access viewOptions() method and mLastReleaseMousePos without making them public
friend class QgsLayerTreeViewItemDelegate; friend class QgsLayerTreeViewItemDelegate;
}; };

View File

@ -28,6 +28,7 @@
#include <QStringList> #include <QStringList>
#include <QSize> #include <QSize>
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include <QDebug>
/*! /*!
Connect to all of the models signals. Whenever anything happens Connect to all of the models signals. Whenever anything happens
@ -493,17 +494,18 @@ void ModelTest::rowsAboutToBeInserted( const QModelIndex &parent, int start, int
void ModelTest::rowsInserted( const QModelIndex &parent, int start, int end ) void ModelTest::rowsInserted( const QModelIndex &parent, int start, int end )
{ {
Changing c = insert.pop(); Changing c = insert.pop();
Q_ASSERT( c.parent == parent ); //*
Q_ASSERT( c.oldSize + ( end - start + 1 ) == model->rowCount( parent ) ); if ( c.next != model->data( model->index( end + 1, 0, c.parent ) ) )
Q_ASSERT( c.last == model->data( model->index( start - 1, 0, c.parent ) ) ); {
/* qDebug() << start << end;
if (c.next != model->data(model->index(end + 1, 0, c.parent))) { for ( int i = 0; i < model->rowCount(); ++i )
qDebug() << start << end; qDebug() << model->index( i, 0 ).data().toString();
for (int i=0; i < model->rowCount(); ++i) qDebug() << c.next << model->data( model->index( end + 1, 0, c.parent ) );
qDebug() << model->index(i, 0).data().toString();
qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent));
} }
*/ //*/
Q_ASSERT( c.parent == parent );
Q_ASSERT_X( c.oldSize + ( end - start + 1 ) == model->rowCount( parent ), "Rows inserted", QStringLiteral( "%1 != %2" ).arg( c.oldSize + ( end - start + 1 ) ).arg( model->rowCount( parent ) ).toStdString().c_str() );
Q_ASSERT( c.last == model->data( model->index( start - 1, 0, c.parent ) ) );
Q_ASSERT( c.next == model->data( model->index( end + 1, 0, c.parent ) ) ); Q_ASSERT( c.next == model->data( model->index( end + 1, 0, c.parent ) ) );
} }
@ -547,7 +549,7 @@ void ModelTest::rowsRemoved( const QModelIndex &parent, int start, int end )
{ {
Changing c = remove.pop(); Changing c = remove.pop();
Q_ASSERT( c.parent == parent ); Q_ASSERT( c.parent == parent );
Q_ASSERT( c.oldSize - ( end - start + 1 ) == model->rowCount( parent ) ); Q_ASSERT_X( c.oldSize - ( end - start + 1 ) == model->rowCount( parent ), "Rows removed", QStringLiteral( "%1 != %2" ).arg( c.oldSize + ( end - start + 1 ) ).arg( model->rowCount( parent ) ).toStdString().c_str() );
Q_ASSERT( c.last == model->data( model->index( start - 1, 0, c.parent ) ) ); Q_ASSERT( c.last == model->data( model->index( start - 1, 0, c.parent ) ) );
Q_ASSERT( c.next == model->data( model->index( start, 0, c.parent ) ) ); Q_ASSERT( c.next == model->data( model->index( start, 0, c.parent ) ) );
} }

View File

@ -509,6 +509,7 @@ class TestQgsLayerTreeView(unittest.TestCase):
view.setModel(self.model) view.setModel(self.model)
if USE_MODEL_TESTER: if USE_MODEL_TESTER:
proxy_tester = QAbstractItemModelTester(view.model()) proxy_tester = QAbstractItemModelTester(view.model())
tree_tester = QAbstractItemModelTester(view.layerTreeModel())
view.setCurrentLayer(self.layer3) view.setCurrentLayer(self.layer3)
self.layer3.setFlags(self.layer.Private) self.layer3.setFlags(self.layer.Private)
@ -520,6 +521,8 @@ class TestQgsLayerTreeView(unittest.TestCase):
view.setModel(self.model) view.setModel(self.model)
if USE_MODEL_TESTER: if USE_MODEL_TESTER:
proxy_tester = QAbstractItemModelTester(view.model()) proxy_tester = QAbstractItemModelTester(view.model())
tree_tester = QAbstractItemModelTester(view.layerTreeModel())
tree_model = view.layerTreeModel() tree_model = view.layerTreeModel()
proxy_model = view.proxyModel() proxy_model = view.proxyModel()