mirror of
https://github.com/qgis/QGIS.git
synced 2025-11-27 00:07:16 -05:00
Merge pull request #39872 from elpaso/hidden-layers-bugfix
Hidden layers bugfix
This commit is contained in:
commit
8c06a1ac43
@ -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 );
|
||||||
|
|||||||
@ -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:
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 );
|
||||||
|
|||||||
@ -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 );
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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 )
|
||||||
|
|||||||
@ -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 )
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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() );
|
||||||
|
|||||||
@ -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 );
|
||||||
|
|||||||
@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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 ) ) );
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user