Skip to content

Commit

Permalink
fix(layertreeview): add checks on nullptr to avoid segfaults
Browse files Browse the repository at this point in the history
check calls to layerTreeModel(), selectedModel(), and use of mProxyModel
  • Loading branch information
Djedouas committed Nov 27, 2024
1 parent 0e03cc6 commit 992c956
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 48 deletions.
167 changes: 119 additions & 48 deletions src/gui/layertree/qgslayertreeview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,14 @@ QgsMapLayer *QgsLayerTreeView::currentLayer() const

void QgsLayerTreeView::setCurrentLayer( QgsMapLayer *layer )
{
if ( !layer )
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layer || !layerModel )
{
setCurrentIndex( QModelIndex() );
return;
}

QgsLayerTreeLayer *nodeLayer = layerTreeModel()->rootGroup()->findLayer( layer->id() );
QgsLayerTreeLayer *nodeLayer = layerModel->rootGroup()->findLayer( layer->id() );
if ( !nodeLayer )
return;

Expand All @@ -167,9 +168,10 @@ void QgsLayerTreeView::setCurrentLayer( QgsMapLayer *layer )

void QgsLayerTreeView::setLayerVisible( QgsMapLayer *layer, bool visible )
{
if ( !layer )
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layer || !layerModel )
return;
QgsLayerTreeLayer *nodeLayer = layerTreeModel()->rootGroup()->findLayer( layer->id() );
QgsLayerTreeLayer *nodeLayer = layerModel->rootGroup()->findLayer( layer->id() );
if ( !nodeLayer )
return;
nodeLayer->setItemVisibilityChecked( visible );
Expand Down Expand Up @@ -199,17 +201,18 @@ void QgsLayerTreeView::contextMenuEvent( QContextMenuEvent *event )
void QgsLayerTreeView::modelRowsInserted( const QModelIndex &index, int start, int end )
{
QgsLayerTreeNode *parentNode = index2node( index );
if ( !parentNode )
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !parentNode || !layerModel )
return;

// Embedded widgets - replace placeholders in the model by actual widgets
if ( layerTreeModel()->testFlag( QgsLayerTreeModel::UseEmbeddedWidgets ) && QgsLayerTree::isLayer( parentNode ) )
if ( layerModel->testFlag( QgsLayerTreeModel::UseEmbeddedWidgets ) && QgsLayerTree::isLayer( parentNode ) )
{
QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( parentNode );
if ( QgsMapLayer *layer = nodeLayer->layer() )
{
const int widgetsCount = layer->customProperty( QStringLiteral( "embeddedWidgets/count" ), 0 ).toInt();
QList<QgsLayerTreeModelLegendNode *> legendNodes = layerTreeModel()->layerLegendNodes( nodeLayer, true );
QList<QgsLayerTreeModelLegendNode *> legendNodes = layerModel->layerLegendNodes( nodeLayer, true );
for ( int i = 0; i < widgetsCount; ++i )
{
const QString providerId = layer->customProperty( QStringLiteral( "embeddedWidgets/%1/id" ).arg( i ) ).toString();
Expand Down Expand Up @@ -247,7 +250,7 @@ void QgsLayerTreeView::modelRowsInserted( const QModelIndex &index, int start, i
if ( expandedNodeKeys.isEmpty() )
return;

const auto constLayerLegendNodes = layerTreeModel()->layerLegendNodes( QgsLayerTree::toLayer( parentNode ), true );
const auto constLayerLegendNodes = layerModel->layerLegendNodes( QgsLayerTree::toLayer( parentNode ), true );
for ( QgsLayerTreeModelLegendNode *legendNode : constLayerLegendNodes )
{
const QString ruleKey = legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
Expand Down Expand Up @@ -300,6 +303,10 @@ void QgsLayerTreeView::updateExpandedStateToNode( const QModelIndex &index )

void QgsLayerTreeView::onCurrentChanged()
{
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layerModel )
return;

QgsMapLayer *layerCurrent = layerForIndex( currentIndex() );
const QString layerCurrentID = layerCurrent ? layerCurrent->id() : QString();
if ( mCurrentLayerID == layerCurrentID )
Expand All @@ -309,20 +316,20 @@ void QgsLayerTreeView::onCurrentChanged()
QModelIndex proxyModelNodeLayerIndex;
if ( layerCurrent )
{
QgsLayerTreeLayer *nodeLayer = layerTreeModel()->rootGroup()->findLayer( layerCurrentID );
QgsLayerTreeLayer *nodeLayer = layerModel->rootGroup()->findLayer( layerCurrentID );
if ( nodeLayer )
proxyModelNodeLayerIndex = node2index( nodeLayer );
}

if ( ! proxyModelNodeLayerIndex.isValid() )
{
mCurrentLayerID = QString();
layerTreeModel()->setCurrentIndex( QModelIndex() );
layerModel->setCurrentIndex( QModelIndex() );
}
else
{
mCurrentLayerID = layerCurrentID;
layerTreeModel()->setCurrentIndex( mProxyModel->mapToSource( proxyModelNodeLayerIndex ) );
layerModel->setCurrentIndex( mProxyModel->mapToSource( proxyModelNodeLayerIndex ) );
}

//checkModel();
Expand All @@ -339,12 +346,13 @@ void QgsLayerTreeView::onExpandedChanged( QgsLayerTreeNode *node, bool expanded

void QgsLayerTreeView::onCustomPropertyChanged( QgsLayerTreeNode *node, const QString &key )
{
if ( key != QLatin1String( "expandedLegendNodes" ) || !QgsLayerTree::isLayer( node ) )
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( key != QLatin1String( "expandedLegendNodes" ) || !QgsLayerTree::isLayer( node ) || !layerModel )
return;

const QSet<QString> expandedLegendNodes = qgis::listToSet( node->customProperty( QStringLiteral( "expandedLegendNodes" ) ).toStringList() );

const QList<QgsLayerTreeModelLegendNode *> legendNodes = layerTreeModel()->layerLegendNodes( QgsLayerTree::toLayer( node ), true );
const QList<QgsLayerTreeModelLegendNode *> legendNodes = layerModel->layerLegendNodes( QgsLayerTree::toLayer( node ), true );
for ( QgsLayerTreeModelLegendNode *legendNode : legendNodes )
{
const QString key = legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
Expand All @@ -355,7 +363,10 @@ void QgsLayerTreeView::onCustomPropertyChanged( QgsLayerTreeNode *node, const QS

void QgsLayerTreeView::onModelReset()
{
updateExpandedStateFromNode( layerTreeModel()->rootGroup() );
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layerModel )
return;
updateExpandedStateFromNode( layerModel->rootGroup() );
//checkModel();
}

Expand Down Expand Up @@ -393,7 +404,10 @@ QgsMapLayer *QgsLayerTreeView::layerForIndex( const QModelIndex &index ) const

QgsLayerTreeNode *QgsLayerTreeView::currentNode() const
{
return index2node( selectionModel()->currentIndex() );
if ( QItemSelectionModel *selectModel = selectionModel() )
return index2node( selectModel->currentIndex() );
else
return nullptr;
}

QgsLayerTreeGroup *QgsLayerTreeView::currentGroupNode() const
Expand All @@ -408,30 +422,43 @@ QgsLayerTreeGroup *QgsLayerTreeView::currentGroupNode() const
return QgsLayerTree::toGroup( parent );
}

if ( QgsLayerTreeModelLegendNode *legendNode = index2legendNode( selectionModel()->currentIndex() ) )
if ( QItemSelectionModel *selectModel = selectionModel() )
{
QgsLayerTreeLayer *parent = legendNode->layerNode();
if ( QgsLayerTree::isGroup( parent->parent() ) )
return QgsLayerTree::toGroup( parent->parent() );
if ( QgsLayerTreeModelLegendNode *legendNode = index2legendNode( selectModel->currentIndex() ) )
{
QgsLayerTreeLayer *parent = legendNode->layerNode();
if ( QgsLayerTree::isGroup( parent->parent() ) )
return QgsLayerTree::toGroup( parent->parent() );
}
}

return nullptr;
}

QgsLayerTreeModelLegendNode *QgsLayerTreeView::currentLegendNode() const
{
return index2legendNode( selectionModel()->currentIndex() );
if ( QItemSelectionModel *selectModel = selectionModel() )
return index2legendNode( selectModel->currentIndex() );
else
return nullptr;
}

QList<QgsLayerTreeNode *> QgsLayerTreeView::selectedNodes( bool skipInternal ) const
{
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layerModel )
return QList<QgsLayerTreeNode *>();

QModelIndexList mapped;
const QModelIndexList selected = selectionModel()->selectedIndexes();
mapped.reserve( selected.size() );
for ( const QModelIndex &index : selected )
mapped << mProxyModel->mapToSource( index );
if ( QItemSelectionModel *selectModel = selectionModel() )
{
const QModelIndexList selected = selectModel->selectedIndexes();
mapped.reserve( selected.size() );
for ( const QModelIndex &index : selected )
mapped << mProxyModel->mapToSource( index );
}

return layerTreeModel()->indexes2nodes( mapped, skipInternal );
return layerModel->indexes2nodes( mapped, skipInternal );
}

QList<QgsLayerTreeLayer *> QgsLayerTreeView::selectedLayerNodes() const
Expand Down Expand Up @@ -463,12 +490,17 @@ QList<QgsMapLayer *> QgsLayerTreeView::selectedLayers() const
QList<QgsLayerTreeModelLegendNode *> QgsLayerTreeView::selectedLegendNodes() const
{
QList<QgsLayerTreeModelLegendNode *> res;
const QModelIndexList selected = selectionModel()->selectedIndexes();
QgsLayerTreeModel *layerModel = layerTreeModel();
QItemSelectionModel *selectModel = selectionModel();
if ( !layerModel || !selectModel )
return res;

const QModelIndexList selected = selectModel->selectedIndexes();
res.reserve( selected.size() );
for ( const QModelIndex &index : selected )
{
const QModelIndex &modelIndex = mProxyModel->mapToSource( index );
if ( QgsLayerTreeModelLegendNode *node = layerTreeModel()->index2legendNode( modelIndex ) )
if ( QgsLayerTreeModelLegendNode *node = layerModel->index2legendNode( modelIndex ) )
{
res.push_back( node );
}
Expand All @@ -480,12 +512,17 @@ QList<QgsLayerTreeModelLegendNode *> QgsLayerTreeView::selectedLegendNodes() con
QList<QgsMapLayer *> QgsLayerTreeView::selectedLayersRecursive() const
{
QModelIndexList mapped;
const QModelIndexList selected = selectionModel()->selectedIndexes();
QgsLayerTreeModel *layerModel = layerTreeModel();
QItemSelectionModel *selectModel = selectionModel();
if ( !layerModel || !selectModel )
return QList<QgsMapLayer *>();

const QModelIndexList selected = selectModel->selectedIndexes();
mapped.reserve( selected.size() );
for ( const QModelIndex &index : selected )
mapped << mProxyModel->mapToSource( index );

const QList<QgsLayerTreeNode *> nodes = layerTreeModel()->indexes2nodes( mapped, false );
const QList<QgsLayerTreeNode *> nodes = layerModel->indexes2nodes( mapped, false );
const QSet<QgsMapLayer *> layersSet = QgsLayerTreeUtils::collectMapLayersRecursive( nodes );
return qgis::setToList( layersSet );
}
Expand Down Expand Up @@ -525,9 +562,12 @@ QStringList QgsLayerTreeView::viewOnlyCustomProperties()

void QgsLayerTreeView::refreshLayerSymbology( const QString &layerId )
{
QgsLayerTreeLayer *nodeLayer = layerTreeModel()->rootGroup()->findLayer( layerId );
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layerModel )
return;
QgsLayerTreeLayer *nodeLayer = layerModel->rootGroup()->findLayer( layerId );
if ( nodeLayer )
layerTreeModel()->refreshLayerLegend( nodeLayer );
layerModel->refreshLayerLegend( nodeLayer );
}


Expand Down Expand Up @@ -567,14 +607,20 @@ static void _expandAllNodes( QgsLayerTreeGroup *parent, bool expanded, QgsLayerT
void QgsLayerTreeView::expandAllNodes()
{
// unfortunately expandAll() does not emit expanded() signals
_expandAllNodes( layerTreeModel()->rootGroup(), true, layerTreeModel() );
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layerModel )
return;
_expandAllNodes( layerModel->rootGroup(), true, layerModel );
expandAll();
}

void QgsLayerTreeView::collapseAllNodes()
{
// unfortunately collapseAll() does not emit collapsed() signals
_expandAllNodes( layerTreeModel()->rootGroup(), false, layerTreeModel() );
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layerModel )
return;
_expandAllNodes( layerModel->rootGroup(), false, layerModel );
collapseAll();
}

Expand All @@ -584,9 +630,12 @@ void QgsLayerTreeView::setMessageBar( QgsMessageBar *messageBar )
return;

mMessageBar = messageBar;
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layerModel )
return;

if ( mMessageBar )
connect( layerTreeModel(), &QgsLayerTreeModel::messageEmitted, this,
connect( layerModel, &QgsLayerTreeModel::messageEmitted, this,
[ = ]( const QString & message, Qgis::MessageLevel level = Qgis::MessageLevel::Info, int duration = 5 )
{
Q_UNUSED( duration )
Expand All @@ -597,6 +646,9 @@ void QgsLayerTreeView::setMessageBar( QgsMessageBar *messageBar )

void QgsLayerTreeView::setShowPrivateLayers( bool showPrivate )
{
if ( !mProxyModel )
return;

mShowPrivateLayers = showPrivate;
mProxyModel->setShowPrivateLayers( showPrivate );
}
Expand All @@ -616,17 +668,21 @@ void QgsLayerTreeView::mouseDoubleClickEvent( QMouseEvent *event )

void QgsLayerTreeView::mouseReleaseEvent( QMouseEvent *event )
{
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layerModel )
return;

// we need to keep last mouse position in order to know whether to emit an indicator's clicked() signal
// (the item delegate needs to know which indicator has been clicked)
mLastReleaseMousePos = event->pos();

const QgsLayerTreeModel::Flags oldFlags = layerTreeModel()->flags();
const QgsLayerTreeModel::Flags oldFlags = layerModel->flags();
if ( event->modifiers() & Qt::ControlModifier )
layerTreeModel()->setFlags( oldFlags | QgsLayerTreeModel::ActionHierarchical );
layerModel->setFlags( oldFlags | QgsLayerTreeModel::ActionHierarchical );
else
layerTreeModel()->setFlags( oldFlags & ~QgsLayerTreeModel::ActionHierarchical );
layerModel->setFlags( oldFlags & ~QgsLayerTreeModel::ActionHierarchical );
QTreeView::mouseReleaseEvent( event );
layerTreeModel()->setFlags( oldFlags );
layerModel->setFlags( oldFlags );
}

void QgsLayerTreeView::keyPressEvent( QKeyEvent *event )
Expand All @@ -648,13 +704,16 @@ void QgsLayerTreeView::keyPressEvent( QKeyEvent *event )
}
}

const QgsLayerTreeModel::Flags oldFlags = layerTreeModel()->flags();
QgsLayerTreeModel *layerModel = layerTreeModel();
if ( !layerModel )
return;
const QgsLayerTreeModel::Flags oldFlags = layerModel->flags();
if ( event->modifiers() & Qt::ControlModifier )
layerTreeModel()->setFlags( oldFlags | QgsLayerTreeModel::ActionHierarchical );
layerModel->setFlags( oldFlags | QgsLayerTreeModel::ActionHierarchical );
else
layerTreeModel()->setFlags( oldFlags & ~QgsLayerTreeModel::ActionHierarchical );
layerModel->setFlags( oldFlags & ~QgsLayerTreeModel::ActionHierarchical );
QTreeView::keyPressEvent( event );
layerTreeModel()->setFlags( oldFlags );
layerModel->setFlags( oldFlags );
}

void QgsLayerTreeView::dragEnterEvent( QDragEnterEvent *event )
Expand Down Expand Up @@ -782,32 +841,44 @@ QgsLayerTreeProxyModel *QgsLayerTreeView::proxyModel() const

QgsLayerTreeNode *QgsLayerTreeView::index2node( const QModelIndex &index ) const
{
return layerTreeModel()->index2node( mProxyModel->mapToSource( index ) );
if ( QgsLayerTreeModel *layerModel = layerTreeModel() )
return layerModel->index2node( mProxyModel->mapToSource( index ) );
return nullptr;
}

QModelIndex QgsLayerTreeView::node2index( QgsLayerTreeNode *node ) const
{
return mProxyModel->mapFromSource( node2sourceIndex( node ) );
if ( mProxyModel )
return mProxyModel->mapFromSource( node2sourceIndex( node ) );
return QModelIndex();
}

QModelIndex QgsLayerTreeView::node2sourceIndex( QgsLayerTreeNode *node ) const
{
return layerTreeModel()->node2index( node );
if ( QgsLayerTreeModel *layerModel = layerTreeModel() )
return layerModel->node2index( node );
return QModelIndex();
}

QgsLayerTreeModelLegendNode *QgsLayerTreeView::index2legendNode( const QModelIndex &index ) const
{
return QgsLayerTreeModel::index2legendNode( mProxyModel->mapToSource( index ) );
if ( mProxyModel )
return QgsLayerTreeModel::index2legendNode( mProxyModel->mapToSource( index ) );
return nullptr;
}

QModelIndex QgsLayerTreeView::legendNode2index( QgsLayerTreeModelLegendNode *legendNode )
{
return mProxyModel->mapFromSource( legendNode2sourceIndex( legendNode ) );
if ( mProxyModel )
return mProxyModel->mapFromSource( legendNode2sourceIndex( legendNode ) );
return QModelIndex();
}

QModelIndex QgsLayerTreeView::legendNode2sourceIndex( QgsLayerTreeModelLegendNode *legendNode )
{
return layerTreeModel()->legendNode2index( legendNode );
if ( QgsLayerTreeModel *layerModel = layerTreeModel() )
return layerModel->legendNode2index( legendNode );
return QModelIndex();
}

QgsLayerTreeProxyModel::QgsLayerTreeProxyModel( QgsLayerTreeModel *treeModel, QObject *parent )
Expand Down
Loading

0 comments on commit 992c956

Please sign in to comment.