LCOV - code coverage report
Current view: top level - core/layertree - qgslayertreemodel.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 997 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :   qgslayertreemodel.cpp
       3                 :            :   --------------------------------------
       4                 :            :   Date                 : May 2014
       5                 :            :   Copyright            : (C) 2014 by Martin Dobias
       6                 :            :   Email                : wonder dot sk at gmail dot com
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : 
      16                 :            : #include <QMimeData>
      17                 :            : #include <QTextStream>
      18                 :            : 
      19                 :            : #include "qgslayertreemodel.h"
      20                 :            : 
      21                 :            : #include "qgsapplication.h"
      22                 :            : #include "qgslayertree.h"
      23                 :            : #include "qgslayertreeutils.h"
      24                 :            : #include "qgslayertreemodellegendnode.h"
      25                 :            : #include "qgsproject.h"
      26                 :            : #include "qgsdataitem.h"
      27                 :            : #include "qgsmaphittest.h"
      28                 :            : #include "qgsmaplayer.h"
      29                 :            : #include "qgsmaplayerlegend.h"
      30                 :            : #include "qgsmaplayerstylemanager.h"
      31                 :            : #include "qgspluginlayer.h"
      32                 :            : #include "qgsrasterlayer.h"
      33                 :            : #include "qgsrenderer.h"
      34                 :            : #include "qgssymbollayerutils.h"
      35                 :            : #include "qgsvectorlayer.h"
      36                 :            : #include "qgslayerdefinition.h"
      37                 :            : 
      38                 :            : 
      39                 :          0 : QgsLayerTreeModel::QgsLayerTreeModel( QgsLayerTree *rootNode, QObject *parent )
      40                 :          0 :   : QAbstractItemModel( parent )
      41                 :          0 :   , mRootNode( rootNode )
      42                 :          0 :   , mFlags( ShowLegend | AllowLegendChangeState | DeferredLegendInvalidation )
      43                 :          0 :   , mAutoCollapseLegendNodesCount( -1 )
      44                 :          0 :   , mLegendFilterByScale( 0 )
      45                 :          0 :   , mLegendFilterUsesExtent( false )
      46                 :          0 :   , mLegendMapViewMupp( 0 )
      47                 :          0 :   , mLegendMapViewDpi( 0 )
      48                 :          0 :   , mLegendMapViewScale( 0 )
      49                 :          0 : {
      50                 :          0 :   connectToRootNode();
      51                 :            : 
      52                 :          0 :   mFontLayer.setBold( true );
      53                 :            : 
      54                 :          0 :   connect( &mDeferLegendInvalidationTimer, &QTimer::timeout, this, &QgsLayerTreeModel::invalidateLegendMapBasedData );
      55                 :          0 :   mDeferLegendInvalidationTimer.setSingleShot( true );
      56                 :          0 : }
      57                 :            : 
      58                 :          0 : QgsLayerTreeModel::~QgsLayerTreeModel()
      59                 :          0 : {
      60                 :          0 :   legendCleanup();
      61                 :          0 : }
      62                 :            : 
      63                 :          0 : QgsLayerTreeNode *QgsLayerTreeModel::index2node( const QModelIndex &index ) const
      64                 :            : {
      65                 :          0 :   if ( !index.isValid() )
      66                 :          0 :     return mRootNode;
      67                 :            : 
      68                 :          0 :   QObject *obj = reinterpret_cast<QObject *>( index.internalPointer() );
      69                 :          0 :   return qobject_cast<QgsLayerTreeNode *>( obj );
      70                 :          0 : }
      71                 :            : 
      72                 :            : 
      73                 :          0 : int QgsLayerTreeModel::rowCount( const QModelIndex &parent ) const
      74                 :            : {
      75                 :          0 :   if ( QgsLayerTreeModelLegendNode *nodeLegend = index2legendNode( parent ) )
      76                 :          0 :     return legendNodeRowCount( nodeLegend );
      77                 :            : 
      78                 :          0 :   QgsLayerTreeNode *n = index2node( parent );
      79                 :          0 :   if ( !n )
      80                 :          0 :     return 0;
      81                 :            : 
      82                 :          0 :   if ( QgsLayerTree::isLayer( n ) )
      83                 :            :   {
      84                 :          0 :     if ( !testFlag( ShowLegend ) )
      85                 :          0 :       return 0;
      86                 :            : 
      87                 :          0 :     return legendRootRowCount( QgsLayerTree::toLayer( n ) );
      88                 :            :   }
      89                 :            : 
      90                 :          0 :   return n->children().count();
      91                 :          0 : }
      92                 :            : 
      93                 :          0 : int QgsLayerTreeModel::columnCount( const QModelIndex &parent ) const
      94                 :            : {
      95                 :          0 :   Q_UNUSED( parent )
      96                 :          0 :   return 1;
      97                 :            : }
      98                 :            : 
      99                 :          0 : QModelIndex QgsLayerTreeModel::index( int row, int column, const QModelIndex &parent ) const
     100                 :            : {
     101                 :          0 :   if ( column < 0 || column >= columnCount( parent ) ||
     102                 :          0 :        row < 0 || row >= rowCount( parent ) )
     103                 :          0 :     return QModelIndex();
     104                 :            : 
     105                 :          0 :   if ( QgsLayerTreeModelLegendNode *nodeLegend = index2legendNode( parent ) )
     106                 :          0 :     return legendNodeIndex( row, column, nodeLegend );
     107                 :            : 
     108                 :          0 :   QgsLayerTreeNode *n = index2node( parent );
     109                 :          0 :   if ( !n )
     110                 :          0 :     return QModelIndex(); // have no children
     111                 :            : 
     112                 :          0 :   if ( testFlag( ShowLegend ) && QgsLayerTree::isLayer( n ) )
     113                 :            :   {
     114                 :          0 :     return legendRootIndex( row, column, QgsLayerTree::toLayer( n ) );
     115                 :            :   }
     116                 :            : 
     117                 :          0 :   return createIndex( row, column, static_cast<QObject *>( n->children().at( row ) ) );
     118                 :          0 : }
     119                 :            : 
     120                 :            : 
     121                 :          0 : QModelIndex QgsLayerTreeModel::parent( const QModelIndex &child ) const
     122                 :            : {
     123                 :          0 :   if ( !child.isValid() )
     124                 :          0 :     return QModelIndex();
     125                 :            : 
     126                 :          0 :   if ( QgsLayerTreeNode *n = index2node( child ) )
     127                 :            :   {
     128                 :          0 :     return indexOfParentLayerTreeNode( n->parent() ); // must not be null
     129                 :            :   }
     130                 :          0 :   else if ( QgsLayerTreeModelLegendNode *legendNode = index2legendNode( child ) )
     131                 :            :   {
     132                 :          0 :     return legendParent( legendNode );
     133                 :            :   }
     134                 :            :   else
     135                 :            :   {
     136                 :            :     Q_ASSERT( false ); // no other node types!
     137                 :          0 :     return QModelIndex();
     138                 :            :   }
     139                 :            : 
     140                 :          0 : }
     141                 :            : 
     142                 :            : 
     143                 :          0 : QModelIndex QgsLayerTreeModel::indexOfParentLayerTreeNode( QgsLayerTreeNode *parentNode ) const
     144                 :            : {
     145                 :            :   Q_ASSERT( parentNode );
     146                 :            : 
     147                 :          0 :   QgsLayerTreeNode *grandParentNode = parentNode->parent();
     148                 :          0 :   if ( !grandParentNode )
     149                 :          0 :     return QModelIndex();  // root node -> invalid index
     150                 :            : 
     151                 :          0 :   int row = grandParentNode->children().indexOf( parentNode );
     152                 :            :   Q_ASSERT( row >= 0 );
     153                 :            : 
     154                 :          0 :   return createIndex( row, 0, static_cast<QObject *>( parentNode ) );
     155                 :          0 : }
     156                 :            : 
     157                 :            : 
     158                 :          0 : QVariant QgsLayerTreeModel::data( const QModelIndex &index, int role ) const
     159                 :            : {
     160                 :          0 :   if ( !index.isValid() || index.column() > 1 )
     161                 :          0 :     return QVariant();
     162                 :            : 
     163                 :          0 :   if ( QgsLayerTreeModelLegendNode *sym = index2legendNode( index ) )
     164                 :          0 :     return legendNodeData( sym, role );
     165                 :            : 
     166                 :          0 :   QgsLayerTreeNode *node = index2node( index );
     167                 :          0 :   if ( role == Qt::DisplayRole || role == Qt::EditRole )
     168                 :            :   {
     169                 :          0 :     if ( QgsLayerTree::isGroup( node ) )
     170                 :          0 :       return QgsLayerTree::toGroup( node )->name();
     171                 :            : 
     172                 :          0 :     if ( QgsLayerTree::isLayer( node ) )
     173                 :            :     {
     174                 :          0 :       QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
     175                 :          0 :       QString name = nodeLayer->name();
     176                 :          0 :       if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt() && role == Qt::DisplayRole )
     177                 :            :       {
     178                 :          0 :         QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() );
     179                 :          0 :         if ( vlayer && vlayer->featureCount() >= 0 )
     180                 :          0 :           name += QStringLiteral( " [%1]" ).arg( vlayer->featureCount() );
     181                 :          0 :       }
     182                 :          0 :       return name;
     183                 :          0 :     }
     184                 :          0 :   }
     185                 :          0 :   else if ( role == Qt::DecorationRole && index.column() == 0 )
     186                 :            :   {
     187                 :          0 :     if ( QgsLayerTree::isGroup( node ) )
     188                 :          0 :       return iconGroup();
     189                 :            : 
     190                 :          0 :     if ( QgsLayerTree::isLayer( node ) )
     191                 :            :     {
     192                 :          0 :       QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
     193                 :            : 
     194                 :          0 :       QgsMapLayer *layer = nodeLayer->layer();
     195                 :          0 :       if ( !layer )
     196                 :          0 :         return QVariant();
     197                 :            : 
     198                 :            :       // icons possibly overriding default icon
     199                 :          0 :       QIcon icon;
     200                 :            : 
     201                 :          0 :       switch ( layer->type() )
     202                 :            :       {
     203                 :            :         case QgsMapLayerType::RasterLayer:
     204                 :          0 :           icon = QgsLayerItem::iconRaster();
     205                 :          0 :           break;
     206                 :            : 
     207                 :            :         case QgsMapLayerType::MeshLayer:
     208                 :          0 :           icon = QgsLayerItem::iconMesh();
     209                 :          0 :           break;
     210                 :            : 
     211                 :            :         case QgsMapLayerType::VectorTileLayer:
     212                 :          0 :           icon = QgsLayerItem::iconVectorTile();
     213                 :          0 :           break;
     214                 :            : 
     215                 :            :         case QgsMapLayerType::PointCloudLayer:
     216                 :          0 :           icon = QgsLayerItem::iconPointCloud();
     217                 :          0 :           break;
     218                 :            : 
     219                 :            :         case QgsMapLayerType::VectorLayer:
     220                 :            :         {
     221                 :          0 :           QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
     222                 :          0 :           if ( vlayer->geometryType() == QgsWkbTypes::PointGeometry )
     223                 :          0 :             icon = QgsLayerItem::iconPoint();
     224                 :          0 :           else if ( vlayer->geometryType() == QgsWkbTypes::LineGeometry )
     225                 :          0 :             icon = QgsLayerItem::iconLine();
     226                 :          0 :           else if ( vlayer->geometryType() == QgsWkbTypes::PolygonGeometry )
     227                 :          0 :             icon = QgsLayerItem::iconPolygon();
     228                 :          0 :           else if ( vlayer->geometryType() == QgsWkbTypes::NullGeometry )
     229                 :          0 :             icon = QgsLayerItem::iconTable();
     230                 :            :           else
     231                 :          0 :             icon = QgsLayerItem::iconDefault();
     232                 :          0 :           break;
     233                 :            :         }
     234                 :            : 
     235                 :            :         case QgsMapLayerType::PluginLayer:
     236                 :            :         case QgsMapLayerType::AnnotationLayer:
     237                 :          0 :           break;
     238                 :            :       }
     239                 :            : 
     240                 :            :       // if there's just on legend entry that should be embedded in layer - do that!
     241                 :          0 :       if ( testFlag( ShowLegend ) && legendEmbeddedInParent( nodeLayer ) )
     242                 :            :       {
     243                 :          0 :         icon = legendIconEmbeddedInParent( nodeLayer );
     244                 :          0 :       }
     245                 :            : 
     246                 :          0 :       QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
     247                 :          0 :       if ( vlayer && vlayer->isEditable() && testFlag( UseTextFormatting ) )
     248                 :            :       {
     249                 :          0 :         const int iconSize = scaleIconSize( 16 );
     250                 :          0 :         QPixmap pixmap( icon.pixmap( iconSize, iconSize ) );
     251                 :            : 
     252                 :          0 :         QPainter painter( &pixmap );
     253                 :          0 :         painter.drawPixmap( 0, 0, iconSize, iconSize, QgsApplication::getThemePixmap( vlayer->isModified() ? QStringLiteral( "/mIconEditableEdits.svg" ) : QStringLiteral( "/mActionToggleEditing.svg" ) ) );
     254                 :          0 :         painter.end();
     255                 :            : 
     256                 :          0 :         icon = QIcon( pixmap );
     257                 :          0 :       }
     258                 :            : 
     259                 :          0 :       return icon;
     260                 :          0 :     }
     261                 :          0 :   }
     262                 :          0 :   else if ( role == Qt::CheckStateRole )
     263                 :            :   {
     264                 :          0 :     if ( !testFlag( AllowNodeChangeVisibility ) )
     265                 :          0 :       return QVariant();
     266                 :            : 
     267                 :          0 :     if ( QgsLayerTree::isLayer( node ) )
     268                 :            :     {
     269                 :          0 :       QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
     270                 :            : 
     271                 :          0 :       if ( nodeLayer->layer() && !nodeLayer->layer()->isSpatial() )
     272                 :          0 :         return QVariant(); // do not show checkbox for non-spatial tables
     273                 :            : 
     274                 :          0 :       return nodeLayer->itemVisibilityChecked() ? Qt::Checked : Qt::Unchecked;
     275                 :            :     }
     276                 :          0 :     else if ( QgsLayerTree::isGroup( node ) )
     277                 :            :     {
     278                 :          0 :       QgsLayerTreeGroup *nodeGroup = QgsLayerTree::toGroup( node );
     279                 :          0 :       return nodeGroup->itemVisibilityChecked() ? Qt::Checked : Qt::Unchecked;
     280                 :            :     }
     281                 :          0 :   }
     282                 :          0 :   else if ( role == Qt::FontRole && testFlag( UseTextFormatting ) )
     283                 :            :   {
     284                 :          0 :     QFont f( QgsLayerTree::isLayer( node ) ? mFontLayer : ( QgsLayerTree::isGroup( node ) ? mFontGroup : QFont() ) );
     285                 :          0 :     if ( index == mCurrentIndex )
     286                 :          0 :       f.setUnderline( true );
     287                 :          0 :     if ( QgsLayerTree::isLayer( node ) )
     288                 :            :     {
     289                 :          0 :       const QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
     290                 :          0 :       if ( ( !node->isVisible() && ( !layer || layer->isSpatial() ) ) || ( layer && !layer->isInScaleRange( mLegendMapViewScale ) ) )
     291                 :            :       {
     292                 :          0 :         f.setItalic( !f.italic() );
     293                 :          0 :       }
     294                 :          0 :     }
     295                 :          0 :     return f;
     296                 :          0 :   }
     297                 :          0 :   else if ( role == Qt::ForegroundRole && testFlag( UseTextFormatting ) )
     298                 :            :   {
     299                 :          0 :     QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
     300                 :          0 :     if ( QgsLayerTree::isLayer( node ) )
     301                 :            :     {
     302                 :          0 :       const QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
     303                 :          0 :       if ( ( !node->isVisible() && ( !layer || layer->isSpatial() ) ) || ( layer && !layer->isInScaleRange( mLegendMapViewScale ) ) )
     304                 :            :       {
     305                 :          0 :         QColor fadedTextColor = brush.color();
     306                 :          0 :         fadedTextColor.setAlpha( 128 );
     307                 :          0 :         brush.setColor( fadedTextColor );
     308                 :          0 :       }
     309                 :          0 :     }
     310                 :          0 :     return brush;
     311                 :          0 :   }
     312                 :          0 :   else if ( role == Qt::ToolTipRole )
     313                 :            :   {
     314                 :          0 :     if ( QgsLayerTree::isLayer( node ) )
     315                 :            :     {
     316                 :          0 :       if ( QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer() )
     317                 :            :       {
     318                 :            :         QString title =
     319                 :          0 :           !layer->title().isEmpty() ? layer->title() :
     320                 :          0 :           !layer->shortName().isEmpty() ? layer->shortName() :
     321                 :          0 :           layer->name();
     322                 :            : 
     323                 :          0 :         title = "<b>" + title.toHtmlEscaped() + "</b>";
     324                 :            : 
     325                 :          0 :         if ( layer->isSpatial() && layer->crs().isValid() )
     326                 :            :         {
     327                 :          0 :           if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
     328                 :          0 :             title += tr( " (%1 - %2)" ).arg( QgsWkbTypes::displayString( vl->wkbType() ), layer->crs().authid() ).toHtmlEscaped();
     329                 :            :           else
     330                 :          0 :             title += tr( " (%1)" ).arg( layer->crs().authid() ).toHtmlEscaped();
     331                 :          0 :         }
     332                 :            : 
     333                 :          0 :         QStringList parts;
     334                 :          0 :         parts << title;
     335                 :            : 
     336                 :          0 :         if ( !layer->abstract().isEmpty() )
     337                 :            :         {
     338                 :          0 :           parts << QString();
     339                 :          0 :           const QStringList abstractLines = layer->abstract().split( '\n' );
     340                 :          0 :           for ( const auto &l : abstractLines )
     341                 :            :           {
     342                 :          0 :             parts << l.toHtmlEscaped();
     343                 :            :           }
     344                 :          0 :           parts << QString();
     345                 :          0 :         }
     346                 :            : 
     347                 :          0 :         QString source( layer->publicSource() );
     348                 :          0 :         if ( source.size() > 1024 )
     349                 :            :         {
     350                 :          0 :           source = source.left( 1023 ) + QString( QChar( 0x2026 ) );
     351                 :          0 :         }
     352                 :            : 
     353                 :          0 :         parts << "<i>" + source.toHtmlEscaped() + "</i>";
     354                 :            : 
     355                 :          0 :         return parts.join( QLatin1String( "<br/>" ) );
     356                 :          0 :       }
     357                 :          0 :     }
     358                 :          0 :   }
     359                 :            : 
     360                 :          0 :   return QVariant();
     361                 :          0 : }
     362                 :            : 
     363                 :            : 
     364                 :          0 : Qt::ItemFlags QgsLayerTreeModel::flags( const QModelIndex &index ) const
     365                 :            : {
     366                 :          0 :   if ( !index.isValid() )
     367                 :            :   {
     368                 :          0 :     Qt::ItemFlags rootFlags = Qt::ItemFlags();
     369                 :          0 :     if ( testFlag( AllowNodeReorder ) )
     370                 :          0 :       rootFlags |= Qt::ItemIsDropEnabled;
     371                 :          0 :     return rootFlags;
     372                 :            :   }
     373                 :            : 
     374                 :          0 :   if ( QgsLayerTreeModelLegendNode *symn = index2legendNode( index ) )
     375                 :          0 :     return legendNodeFlags( symn );
     376                 :            : 
     377                 :          0 :   Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
     378                 :            : 
     379                 :          0 :   if ( testFlag( AllowNodeRename ) )
     380                 :          0 :     f |= Qt::ItemIsEditable;
     381                 :            : 
     382                 :          0 :   QgsLayerTreeNode *node = index2node( index );
     383                 :          0 :   bool isEmbedded = node->customProperty( QStringLiteral( "embedded" ) ).toInt();
     384                 :            : 
     385                 :          0 :   if ( testFlag( AllowNodeReorder ) )
     386                 :            :   {
     387                 :            :     // only root embedded nodes can be reordered
     388                 :          0 :     if ( !isEmbedded || ( isEmbedded && node->parent() && !node->parent()->customProperty( QStringLiteral( "embedded" ) ).toInt() ) )
     389                 :          0 :       f |= Qt::ItemIsDragEnabled;
     390                 :          0 :   }
     391                 :            : 
     392                 :          0 :   if ( testFlag( AllowNodeChangeVisibility ) && ( QgsLayerTree::isLayer( node ) || QgsLayerTree::isGroup( node ) ) )
     393                 :          0 :     f |= Qt::ItemIsUserCheckable;
     394                 :            : 
     395                 :          0 :   if ( testFlag( AllowNodeReorder ) && QgsLayerTree::isGroup( node ) && !isEmbedded )
     396                 :          0 :     f |= Qt::ItemIsDropEnabled;
     397                 :            : 
     398                 :          0 :   return f;
     399                 :          0 : }
     400                 :            : 
     401                 :          0 : bool QgsLayerTreeModel::setData( const QModelIndex &index, const QVariant &value, int role )
     402                 :            : {
     403                 :          0 :   QgsLayerTreeModelLegendNode *sym = index2legendNode( index );
     404                 :          0 :   if ( sym )
     405                 :            :   {
     406                 :          0 :     if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
     407                 :          0 :       return false;
     408                 :          0 :     bool res = sym->setData( value, role );
     409                 :          0 :     if ( res )
     410                 :          0 :       emit dataChanged( index, index );
     411                 :          0 :     return res;
     412                 :            :   }
     413                 :            : 
     414                 :          0 :   QgsLayerTreeNode *node = index2node( index );
     415                 :          0 :   if ( !node )
     416                 :          0 :     return QAbstractItemModel::setData( index, value, role );
     417                 :            : 
     418                 :          0 :   if ( role == Qt::CheckStateRole )
     419                 :            :   {
     420                 :          0 :     if ( !testFlag( AllowNodeChangeVisibility ) )
     421                 :          0 :       return false;
     422                 :            : 
     423                 :          0 :     bool checked = static_cast< Qt::CheckState >( value.toInt() ) == Qt::Checked;
     424                 :          0 :     if ( checked &&  node->children().isEmpty() )
     425                 :            :     {
     426                 :          0 :       node->setItemVisibilityCheckedParentRecursive( checked );
     427                 :          0 :     }
     428                 :          0 :     else if ( testFlag( ActionHierarchical ) )
     429                 :            :     {
     430                 :          0 :       if ( node->children().isEmpty() )
     431                 :          0 :         node->setItemVisibilityCheckedParentRecursive( checked );
     432                 :            :       else
     433                 :          0 :         node->setItemVisibilityCheckedRecursive( checked );
     434                 :          0 :     }
     435                 :            :     else
     436                 :            :     {
     437                 :          0 :       node->setItemVisibilityChecked( checked );
     438                 :            :     }
     439                 :            : 
     440                 :          0 :     recursivelyEmitDataChanged( index );
     441                 :            : 
     442                 :          0 :     return true;
     443                 :            :   }
     444                 :          0 :   else if ( role == Qt::EditRole )
     445                 :            :   {
     446                 :          0 :     if ( !testFlag( AllowNodeRename ) )
     447                 :          0 :       return false;
     448                 :            : 
     449                 :          0 :     if ( QgsLayerTree::isLayer( node ) )
     450                 :            :     {
     451                 :          0 :       QgsLayerTreeLayer *layer = QgsLayerTree::toLayer( node );
     452                 :          0 :       layer->setName( value.toString() );
     453                 :          0 :       emit dataChanged( index, index );
     454                 :          0 :     }
     455                 :          0 :     else if ( QgsLayerTree::isGroup( node ) )
     456                 :            :     {
     457                 :          0 :       QgsLayerTree::toGroup( node )->setName( value.toString() );
     458                 :          0 :       emit dataChanged( index, index );
     459                 :          0 :     }
     460                 :          0 :   }
     461                 :            : 
     462                 :          0 :   return QAbstractItemModel::setData( index, value, role );
     463                 :          0 : }
     464                 :            : 
     465                 :          0 : QModelIndex QgsLayerTreeModel::node2index( QgsLayerTreeNode *node ) const
     466                 :            : {
     467                 :          0 :   if ( !node || !node->parent() )
     468                 :          0 :     return QModelIndex(); // this is the only root item -> invalid index
     469                 :            : 
     470                 :          0 :   QModelIndex parentIndex = node2index( node->parent() );
     471                 :            : 
     472                 :          0 :   int row = node->parent()->children().indexOf( node );
     473                 :            :   Q_ASSERT( row >= 0 );
     474                 :          0 :   return index( row, 0, parentIndex );
     475                 :          0 : }
     476                 :            : 
     477                 :            : 
     478                 :          0 : static bool _isChildOfNode( QgsLayerTreeNode *child, QgsLayerTreeNode *node )
     479                 :            : {
     480                 :          0 :   if ( !child->parent() )
     481                 :          0 :     return false;
     482                 :            : 
     483                 :          0 :   if ( child->parent() == node )
     484                 :          0 :     return true;
     485                 :            : 
     486                 :          0 :   return _isChildOfNode( child->parent(), node );
     487                 :          0 : }
     488                 :            : 
     489                 :          0 : static bool _isChildOfNodes( QgsLayerTreeNode *child, const QList<QgsLayerTreeNode *> &nodes )
     490                 :            : {
     491                 :          0 :   for ( QgsLayerTreeNode *n : nodes )
     492                 :            :   {
     493                 :          0 :     if ( _isChildOfNode( child, n ) )
     494                 :          0 :       return true;
     495                 :            :   }
     496                 :            : 
     497                 :          0 :   return false;
     498                 :          0 : }
     499                 :            : 
     500                 :            : 
     501                 :          0 : QList<QgsLayerTreeNode *> QgsLayerTreeModel::indexes2nodes( const QModelIndexList &list, bool skipInternal ) const
     502                 :            : {
     503                 :          0 :   QList<QgsLayerTreeNode *> nodes;
     504                 :          0 :   const auto constList = list;
     505                 :          0 :   for ( const QModelIndex &index : constList )
     506                 :            :   {
     507                 :          0 :     QgsLayerTreeNode *node = index2node( index );
     508                 :          0 :     if ( !node )
     509                 :          0 :       continue;
     510                 :            : 
     511                 :          0 :     nodes << node;
     512                 :            :   }
     513                 :            : 
     514                 :          0 :   if ( !skipInternal )
     515                 :          0 :     return nodes;
     516                 :            : 
     517                 :            :   // remove any children of nodes if both parent node and children are selected
     518                 :          0 :   QList<QgsLayerTreeNode *> nodesFinal;
     519                 :          0 :   for ( QgsLayerTreeNode *node : std::as_const( nodes ) )
     520                 :            :   {
     521                 :          0 :     if ( !_isChildOfNodes( node, nodes ) )
     522                 :          0 :       nodesFinal << node;
     523                 :            :   }
     524                 :            : 
     525                 :          0 :   return nodesFinal;
     526                 :          0 : }
     527                 :            : 
     528                 :          0 : QgsLayerTree *QgsLayerTreeModel::rootGroup() const
     529                 :            : {
     530                 :          0 :   return mRootNode;
     531                 :            : }
     532                 :            : 
     533                 :          0 : void QgsLayerTreeModel::setRootGroup( QgsLayerTree *newRootGroup )
     534                 :            : {
     535                 :          0 :   beginResetModel();
     536                 :            : 
     537                 :          0 :   disconnectFromRootNode();
     538                 :            : 
     539                 :            :   Q_ASSERT( mLegend.isEmpty() );
     540                 :            : 
     541                 :          0 :   mRootNode = newRootGroup;
     542                 :            : 
     543                 :          0 :   endResetModel();
     544                 :            : 
     545                 :          0 :   connectToRootNode();
     546                 :          0 : }
     547                 :            : 
     548                 :          0 : void QgsLayerTreeModel::refreshLayerLegend( QgsLayerTreeLayer *nodeLayer )
     549                 :            : {
     550                 :            :   // update title
     551                 :          0 :   QModelIndex idx = node2index( nodeLayer );
     552                 :          0 :   emit dataChanged( idx, idx );
     553                 :            : 
     554                 :            :   // update children
     555                 :          0 :   int oldNodeCount = rowCount( idx );
     556                 :          0 :   if ( oldNodeCount > 0 )
     557                 :            :   {
     558                 :          0 :     beginRemoveRows( idx, 0, oldNodeCount - 1 );
     559                 :          0 :     removeLegendFromLayer( nodeLayer );
     560                 :          0 :     endRemoveRows();
     561                 :          0 :   }
     562                 :            : 
     563                 :          0 :   addLegendToLayer( nodeLayer );
     564                 :          0 :   int newNodeCount = rowCount( idx );
     565                 :            : 
     566                 :            :   // automatic collapse of legend nodes - useful if a layer has many legend nodes
     567                 :          0 :   if ( mAutoCollapseLegendNodesCount != -1 && oldNodeCount != newNodeCount && newNodeCount >= mAutoCollapseLegendNodesCount )
     568                 :          0 :     nodeLayer->setExpanded( false );
     569                 :          0 : }
     570                 :            : 
     571                 :          0 : QModelIndex QgsLayerTreeModel::currentIndex() const
     572                 :            : {
     573                 :          0 :   return mCurrentIndex;
     574                 :            : }
     575                 :            : 
     576                 :          0 : void QgsLayerTreeModel::setCurrentIndex( const QModelIndex &currentIndex )
     577                 :            : {
     578                 :          0 :   mCurrentIndex = currentIndex;
     579                 :          0 : }
     580                 :            : 
     581                 :            : 
     582                 :          0 : void QgsLayerTreeModel::setLayerTreeNodeFont( int nodeType, const QFont &font )
     583                 :            : {
     584                 :          0 :   if ( nodeType == QgsLayerTreeNode::NodeGroup )
     585                 :            :   {
     586                 :          0 :     if ( mFontGroup != font )
     587                 :            :     {
     588                 :          0 :       mFontGroup = font;
     589                 :          0 :       recursivelyEmitDataChanged();
     590                 :          0 :     }
     591                 :          0 :   }
     592                 :          0 :   else if ( nodeType == QgsLayerTreeNode::NodeLayer )
     593                 :            :   {
     594                 :          0 :     if ( mFontLayer != font )
     595                 :            :     {
     596                 :          0 :       mFontLayer = font;
     597                 :          0 :       recursivelyEmitDataChanged();
     598                 :          0 :     }
     599                 :          0 :   }
     600                 :            :   else
     601                 :            :   {
     602                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "invalid node type" ), 4 );
     603                 :            :   }
     604                 :          0 : }
     605                 :            : 
     606                 :            : 
     607                 :          0 : QFont QgsLayerTreeModel::layerTreeNodeFont( int nodeType ) const
     608                 :            : {
     609                 :          0 :   if ( nodeType == QgsLayerTreeNode::NodeGroup )
     610                 :          0 :     return mFontGroup;
     611                 :          0 :   else if ( nodeType == QgsLayerTreeNode::NodeLayer )
     612                 :          0 :     return mFontLayer;
     613                 :            :   else
     614                 :            :   {
     615                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "invalid node type" ), 4 );
     616                 :          0 :     return QFont();
     617                 :            :   }
     618                 :          0 : }
     619                 :            : 
     620                 :          0 : void QgsLayerTreeModel::setLegendFilterByScale( double scale )
     621                 :            : {
     622                 :          0 :   mLegendFilterByScale = scale;
     623                 :            : 
     624                 :            :   // this could be later done in more efficient way
     625                 :            :   // by just updating active legend nodes, without refreshing original legend nodes
     626                 :          0 :   const auto layers = mRootNode->findLayers();
     627                 :          0 :   for ( QgsLayerTreeLayer *nodeLayer : layers )
     628                 :          0 :     refreshLayerLegend( nodeLayer );
     629                 :          0 : }
     630                 :            : 
     631                 :          0 : void QgsLayerTreeModel::setLegendFilterByMap( const QgsMapSettings *settings )
     632                 :            : {
     633                 :          0 :   setLegendFilter( settings, /* useExtent = */ true );
     634                 :          0 : }
     635                 :            : 
     636                 :          0 : void QgsLayerTreeModel::setLegendFilter( const QgsMapSettings *settings, bool useExtent, const QgsGeometry &polygon, bool useExpressions )
     637                 :            : {
     638                 :          0 :   if ( settings && settings->hasValidSettings() )
     639                 :            :   {
     640                 :          0 :     mLegendFilterMapSettings.reset( new QgsMapSettings( *settings ) );
     641                 :          0 :     mLegendFilterMapSettings->setLayerStyleOverrides( mLayerStyleOverrides );
     642                 :          0 :     QgsMapHitTest::LayerFilterExpression exprs;
     643                 :          0 :     mLegendFilterUsesExtent = useExtent;
     644                 :            :     // collect expression filters
     645                 :          0 :     if ( useExpressions )
     646                 :            :     {
     647                 :          0 :       const auto layers = mRootNode->findLayers();
     648                 :          0 :       for ( QgsLayerTreeLayer *nodeLayer : layers )
     649                 :            :       {
     650                 :            :         bool enabled;
     651                 :          0 :         QString expr = QgsLayerTreeUtils::legendFilterByExpression( *nodeLayer, &enabled );
     652                 :          0 :         if ( enabled && !expr.isEmpty() )
     653                 :            :         {
     654                 :          0 :           exprs[ nodeLayer->layerId()] = expr;
     655                 :          0 :         }
     656                 :          0 :       }
     657                 :          0 :     }
     658                 :          0 :     bool polygonValid = !polygon.isNull() && polygon.type() == QgsWkbTypes::PolygonGeometry;
     659                 :          0 :     if ( useExpressions && !useExtent && !polygonValid ) // only expressions
     660                 :            :     {
     661                 :          0 :       mLegendFilterHitTest.reset( new QgsMapHitTest( *mLegendFilterMapSettings, exprs ) );
     662                 :          0 :     }
     663                 :            :     else
     664                 :            :     {
     665                 :          0 :       mLegendFilterHitTest.reset( new QgsMapHitTest( *mLegendFilterMapSettings, polygon, exprs ) );
     666                 :            :     }
     667                 :          0 :     mLegendFilterHitTest->run();
     668                 :          0 :   }
     669                 :            :   else
     670                 :            :   {
     671                 :          0 :     if ( !mLegendFilterMapSettings )
     672                 :          0 :       return; // no change
     673                 :            : 
     674                 :          0 :     mLegendFilterMapSettings.reset();
     675                 :          0 :     mLegendFilterHitTest.reset();
     676                 :            :   }
     677                 :            : 
     678                 :            :   // temporarily disable autocollapse so that legend nodes stay visible
     679                 :          0 :   int bkAutoCollapse = autoCollapseLegendNodes();
     680                 :          0 :   setAutoCollapseLegendNodes( -1 );
     681                 :            : 
     682                 :            :   // this could be later done in more efficient way
     683                 :            :   // by just updating active legend nodes, without refreshing original legend nodes
     684                 :          0 :   const auto layers = mRootNode->findLayers();
     685                 :          0 :   for ( QgsLayerTreeLayer *nodeLayer : layers )
     686                 :          0 :     refreshLayerLegend( nodeLayer );
     687                 :            : 
     688                 :          0 :   setAutoCollapseLegendNodes( bkAutoCollapse );
     689                 :          0 : }
     690                 :            : 
     691                 :          0 : void QgsLayerTreeModel::setLegendMapViewData( double mapUnitsPerPixel, int dpi, double scale )
     692                 :            : {
     693                 :          0 :   if ( mLegendMapViewDpi == dpi && qgsDoubleNear( mLegendMapViewMupp, mapUnitsPerPixel ) && qgsDoubleNear( mLegendMapViewScale, scale ) )
     694                 :          0 :     return;
     695                 :            : 
     696                 :          0 :   double previousScale = mLegendMapViewScale;
     697                 :          0 :   mLegendMapViewScale = scale;
     698                 :          0 :   mLegendMapViewMupp = mapUnitsPerPixel;
     699                 :          0 :   mLegendMapViewDpi = dpi;
     700                 :            : 
     701                 :            :   // now invalidate legend nodes!
     702                 :          0 :   legendInvalidateMapBasedData();
     703                 :            : 
     704                 :          0 :   if ( scale != previousScale )
     705                 :          0 :     refreshScaleBasedLayers( QModelIndex(), previousScale );
     706                 :          0 : }
     707                 :            : 
     708                 :          0 : void QgsLayerTreeModel::legendMapViewData( double *mapUnitsPerPixel, int *dpi, double *scale ) const
     709                 :            : {
     710                 :          0 :   if ( mapUnitsPerPixel ) *mapUnitsPerPixel = mLegendMapViewMupp;
     711                 :          0 :   if ( dpi ) *dpi = mLegendMapViewDpi;
     712                 :          0 :   if ( scale ) *scale = mLegendMapViewScale;
     713                 :          0 : }
     714                 :            : 
     715                 :          0 : QMap<QString, QString> QgsLayerTreeModel::layerStyleOverrides() const
     716                 :            : {
     717                 :          0 :   return mLayerStyleOverrides;
     718                 :            : }
     719                 :            : 
     720                 :          0 : void QgsLayerTreeModel::setLayerStyleOverrides( const QMap<QString, QString> &overrides )
     721                 :            : {
     722                 :          0 :   mLayerStyleOverrides = overrides;
     723                 :          0 : }
     724                 :            : 
     725                 :          0 : int QgsLayerTreeModel::scaleIconSize( int standardSize )
     726                 :            : {
     727                 :          0 :   return QgsApplication::scaleIconSize( standardSize, true );
     728                 :            : }
     729                 :            : 
     730                 :          0 : void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
     731                 :            : {
     732                 :          0 :   beginInsertRows( node2index( node ), indexFrom, indexTo );
     733                 :          0 : }
     734                 :            : 
     735                 :          0 : static QList<QgsLayerTreeLayer *> _layerNodesInSubtree( QgsLayerTreeNode *node, int indexFrom, int indexTo )
     736                 :            : {
     737                 :          0 :   QList<QgsLayerTreeNode *> children = node->children();
     738                 :          0 :   QList<QgsLayerTreeLayer *> newLayerNodes;
     739                 :          0 :   for ( int i = indexFrom; i <= indexTo; ++i )
     740                 :            :   {
     741                 :          0 :     QgsLayerTreeNode *child = children.at( i );
     742                 :          0 :     if ( QgsLayerTree::isLayer( child ) )
     743                 :          0 :       newLayerNodes << QgsLayerTree::toLayer( child );
     744                 :          0 :     else if ( QgsLayerTree::isGroup( child ) )
     745                 :          0 :       newLayerNodes << QgsLayerTree::toGroup( child )->findLayers();
     746                 :          0 :   }
     747                 :          0 :   return newLayerNodes;
     748                 :          0 : }
     749                 :            : 
     750                 :          0 : void QgsLayerTreeModel::nodeAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
     751                 :            : {
     752                 :            :   Q_ASSERT( node );
     753                 :            : 
     754                 :          0 :   endInsertRows();
     755                 :            : 
     756                 :          0 :   const auto subNodes = _layerNodesInSubtree( node, indexFrom, indexTo );
     757                 :          0 :   for ( QgsLayerTreeLayer *newLayerNode : subNodes )
     758                 :          0 :     connectToLayer( newLayerNode );
     759                 :          0 : }
     760                 :            : 
     761                 :          0 : void QgsLayerTreeModel::nodeWillRemoveChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
     762                 :            : {
     763                 :            :   Q_ASSERT( node );
     764                 :            : 
     765                 :          0 :   beginRemoveRows( node2index( node ), indexFrom, indexTo );
     766                 :            : 
     767                 :            :   // disconnect from layers and remove their legend
     768                 :          0 :   const auto subNodes = _layerNodesInSubtree( node, indexFrom, indexTo );
     769                 :          0 :   for ( QgsLayerTreeLayer *nodeLayer : subNodes )
     770                 :          0 :     disconnectFromLayer( nodeLayer );
     771                 :          0 : }
     772                 :            : 
     773                 :          0 : void QgsLayerTreeModel::nodeRemovedChildren()
     774                 :            : {
     775                 :          0 :   endRemoveRows();
     776                 :          0 : }
     777                 :            : 
     778                 :          0 : void QgsLayerTreeModel::nodeVisibilityChanged( QgsLayerTreeNode *node )
     779                 :            : {
     780                 :            :   Q_ASSERT( node );
     781                 :            : 
     782                 :          0 :   const QModelIndex index = node2index( node );
     783                 :          0 :   emit dataChanged( index, index );
     784                 :          0 : }
     785                 :            : 
     786                 :          0 : void QgsLayerTreeModel::nodeNameChanged( QgsLayerTreeNode *node, const QString &name )
     787                 :            : {
     788                 :          0 :   Q_UNUSED( name )
     789                 :            :   Q_ASSERT( node );
     790                 :            : 
     791                 :          0 :   const QModelIndex index = node2index( node );
     792                 :          0 :   emit dataChanged( index, index );
     793                 :          0 : }
     794                 :            : 
     795                 :            : 
     796                 :          0 : void QgsLayerTreeModel::nodeCustomPropertyChanged( QgsLayerTreeNode *node, const QString &key )
     797                 :            : {
     798                 :          0 :   if ( QgsLayerTree::isLayer( node ) && key == QLatin1String( "showFeatureCount" ) )
     799                 :          0 :     refreshLayerLegend( QgsLayerTree::toLayer( node ) );
     800                 :          0 : }
     801                 :            : 
     802                 :            : 
     803                 :          0 : void QgsLayerTreeModel::nodeLayerLoaded()
     804                 :            : {
     805                 :          0 :   QgsLayerTreeLayer *nodeLayer = qobject_cast<QgsLayerTreeLayer *>( sender() );
     806                 :          0 :   if ( !nodeLayer )
     807                 :          0 :     return;
     808                 :            : 
     809                 :            :   // deferred connection to the layer
     810                 :          0 :   connectToLayer( nodeLayer );
     811                 :          0 : }
     812                 :            : 
     813                 :          0 : void QgsLayerTreeModel::nodeLayerWillBeUnloaded()
     814                 :            : {
     815                 :          0 :   QgsLayerTreeLayer *nodeLayer = qobject_cast<QgsLayerTreeLayer *>( sender() );
     816                 :          0 :   if ( !nodeLayer )
     817                 :          0 :     return;
     818                 :            : 
     819                 :          0 :   disconnectFromLayer( nodeLayer );
     820                 :            : 
     821                 :            :   // wait for the layer to appear again
     822                 :          0 :   connect( nodeLayer, &QgsLayerTreeLayer::layerLoaded, this, &QgsLayerTreeModel::nodeLayerLoaded );
     823                 :          0 : }
     824                 :            : 
     825                 :          0 : void QgsLayerTreeModel::layerLegendChanged()
     826                 :            : {
     827                 :          0 :   if ( !mRootNode )
     828                 :          0 :     return;
     829                 :            : 
     830                 :          0 :   if ( !testFlag( ShowLegend ) )
     831                 :          0 :     return;
     832                 :            : 
     833                 :          0 :   QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
     834                 :          0 :   if ( !layer )
     835                 :          0 :     return;
     836                 :            : 
     837                 :          0 :   QgsLayerTreeLayer *nodeLayer = mRootNode->findLayer( layer->id() );
     838                 :          0 :   if ( !nodeLayer )
     839                 :          0 :     return;
     840                 :            : 
     841                 :          0 :   refreshLayerLegend( nodeLayer );
     842                 :          0 : }
     843                 :            : 
     844                 :          0 : void QgsLayerTreeModel::layerFlagsChanged()
     845                 :            : {
     846                 :          0 :   if ( !mRootNode )
     847                 :          0 :     return;
     848                 :            : 
     849                 :          0 :   QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
     850                 :          0 :   if ( !layer )
     851                 :          0 :     return;
     852                 :            : 
     853                 :          0 :   QgsLayerTreeLayer *nodeLayer = mRootNode->findLayer( layer->id() );
     854                 :          0 :   if ( !nodeLayer )
     855                 :          0 :     return;
     856                 :            : 
     857                 :          0 :   const QModelIndex index = node2index( nodeLayer );
     858                 :          0 :   emit dataChanged( index, index );
     859                 :          0 : }
     860                 :            : 
     861                 :          0 : void QgsLayerTreeModel::layerNeedsUpdate()
     862                 :            : {
     863                 :          0 :   QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
     864                 :          0 :   if ( !layer )
     865                 :          0 :     return;
     866                 :            : 
     867                 :          0 :   QgsLayerTreeLayer *nodeLayer = mRootNode->findLayer( layer->id() );
     868                 :          0 :   if ( !nodeLayer )
     869                 :          0 :     return;
     870                 :            : 
     871                 :          0 :   QModelIndex index = node2index( nodeLayer );
     872                 :          0 :   emit dataChanged( index, index );
     873                 :            : 
     874                 :          0 :   if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ) ).toInt() )
     875                 :          0 :     refreshLayerLegend( nodeLayer );
     876                 :          0 : }
     877                 :            : 
     878                 :            : 
     879                 :          0 : void QgsLayerTreeModel::legendNodeDataChanged()
     880                 :            : {
     881                 :          0 :   QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( sender() );
     882                 :          0 :   if ( !legendNode )
     883                 :          0 :     return;
     884                 :            : 
     885                 :          0 :   QModelIndex index = legendNode2index( legendNode );
     886                 :          0 :   if ( index.isValid() )
     887                 :          0 :     emit dataChanged( index, index );
     888                 :          0 : }
     889                 :            : 
     890                 :          0 : void QgsLayerTreeModel::legendNodeSizeChanged()
     891                 :            : {
     892                 :          0 :   QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( sender() );
     893                 :          0 :   if ( !legendNode )
     894                 :          0 :     return;
     895                 :            : 
     896                 :          0 :   QModelIndex index = legendNode2index( legendNode );
     897                 :          0 :   if ( index.isValid() )
     898                 :          0 :     emit dataChanged( index, index, QVector<int> { Qt::SizeHintRole } );
     899                 :          0 : }
     900                 :            : 
     901                 :            : 
     902                 :          0 : void QgsLayerTreeModel::connectToLayer( QgsLayerTreeLayer *nodeLayer )
     903                 :            : {
     904                 :          0 :   if ( !nodeLayer->layer() )
     905                 :            :   {
     906                 :            :     // in order to connect to layer, we need to have it loaded.
     907                 :            :     // keep an eye on the layer ID: once loaded, we will use it
     908                 :          0 :     connect( nodeLayer, &QgsLayerTreeLayer::layerLoaded, this, &QgsLayerTreeModel::nodeLayerLoaded, Qt::UniqueConnection );
     909                 :          0 :     return;
     910                 :            :   }
     911                 :            : 
     912                 :            :   // watch if the layer is getting removed
     913                 :          0 :   connect( nodeLayer, &QgsLayerTreeLayer::layerWillBeUnloaded, this, &QgsLayerTreeModel::nodeLayerWillBeUnloaded, Qt::UniqueConnection );
     914                 :            : 
     915                 :          0 :   if ( testFlag( ShowLegend ) )
     916                 :            :   {
     917                 :          0 :     addLegendToLayer( nodeLayer );
     918                 :            : 
     919                 :            :     // automatic collapse of legend nodes - useful if a layer has many legend nodes
     920                 :          0 :     if ( !mRootNode->customProperty( QStringLiteral( "loading" ) ).toBool() )
     921                 :            :     {
     922                 :          0 :       if ( mAutoCollapseLegendNodesCount != -1 && rowCount( node2index( nodeLayer ) )  >= mAutoCollapseLegendNodesCount )
     923                 :          0 :         nodeLayer->setExpanded( false );
     924                 :          0 :     }
     925                 :          0 :   }
     926                 :            : 
     927                 :          0 :   QgsMapLayer *layer = nodeLayer->layer();
     928                 :          0 :   connect( layer, &QgsMapLayer::legendChanged, this, &QgsLayerTreeModel::layerLegendChanged, Qt::UniqueConnection );
     929                 :          0 :   connect( layer, &QgsMapLayer::flagsChanged, this, &QgsLayerTreeModel::layerFlagsChanged, Qt::UniqueConnection );
     930                 :            : 
     931                 :          0 :   if ( layer->type() == QgsMapLayerType::VectorLayer )
     932                 :            :   {
     933                 :            :     // using unique connection because there may be temporarily more nodes for a layer than just one
     934                 :            :     // which would create multiple connections, however disconnect() would disconnect all multiple connections
     935                 :            :     // even if we wanted to disconnect just one connection in each call.
     936                 :          0 :     QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer );
     937                 :          0 :     connect( vl, &QgsVectorLayer::editingStarted, this, &QgsLayerTreeModel::layerNeedsUpdate, Qt::UniqueConnection );
     938                 :          0 :     connect( vl, &QgsVectorLayer::editingStopped, this, &QgsLayerTreeModel::layerNeedsUpdate, Qt::UniqueConnection );
     939                 :          0 :     connect( vl, &QgsVectorLayer::layerModified, this, &QgsLayerTreeModel::layerNeedsUpdate, Qt::UniqueConnection );
     940                 :          0 :   }
     941                 :            : 
     942                 :          0 :   emit dataChanged( node2index( nodeLayer ), node2index( nodeLayer ) );
     943                 :          0 : }
     944                 :            : 
     945                 :            : // try to find out if the layer ID is present in the tree multiple times
     946                 :          0 : static int _numLayerCount( QgsLayerTreeGroup *group, const QString &layerId )
     947                 :            : {
     948                 :          0 :   int count = 0;
     949                 :          0 :   const auto constChildren = group->children();
     950                 :          0 :   for ( QgsLayerTreeNode *child : constChildren )
     951                 :            :   {
     952                 :          0 :     if ( QgsLayerTree::isLayer( child ) )
     953                 :            :     {
     954                 :          0 :       if ( QgsLayerTree::toLayer( child )->layerId() == layerId )
     955                 :          0 :         count++;
     956                 :          0 :     }
     957                 :          0 :     else if ( QgsLayerTree::isGroup( child ) )
     958                 :            :     {
     959                 :          0 :       count += _numLayerCount( QgsLayerTree::toGroup( child ), layerId );
     960                 :          0 :     }
     961                 :            :   }
     962                 :          0 :   return count;
     963                 :          0 : }
     964                 :            : 
     965                 :          0 : void QgsLayerTreeModel::disconnectFromLayer( QgsLayerTreeLayer *nodeLayer )
     966                 :            : {
     967                 :          0 :   disconnect( nodeLayer, nullptr, this, nullptr ); // disconnect from delayed load of layer
     968                 :            : 
     969                 :          0 :   if ( !nodeLayer->layer() )
     970                 :          0 :     return; // we were never connected
     971                 :            : 
     972                 :          0 :   if ( testFlag( ShowLegend ) )
     973                 :            :   {
     974                 :          0 :     removeLegendFromLayer( nodeLayer );
     975                 :          0 :   }
     976                 :            : 
     977                 :          0 :   if ( _numLayerCount( mRootNode, nodeLayer->layerId() ) == 1 )
     978                 :            :   {
     979                 :            :     // last instance of the layer in the tree: disconnect from all signals from layer!
     980                 :          0 :     disconnect( nodeLayer->layer(), nullptr, this, nullptr );
     981                 :          0 :   }
     982                 :          0 : }
     983                 :            : 
     984                 :          0 : void QgsLayerTreeModel::connectToLayers( QgsLayerTreeGroup *parentGroup )
     985                 :            : {
     986                 :          0 :   const auto constChildren = parentGroup->children();
     987                 :          0 :   for ( QgsLayerTreeNode *node : constChildren )
     988                 :            :   {
     989                 :          0 :     if ( QgsLayerTree::isGroup( node ) )
     990                 :          0 :       connectToLayers( QgsLayerTree::toGroup( node ) );
     991                 :          0 :     else if ( QgsLayerTree::isLayer( node ) )
     992                 :          0 :       connectToLayer( QgsLayerTree::toLayer( node ) );
     993                 :            :   }
     994                 :          0 : }
     995                 :            : 
     996                 :          0 : void QgsLayerTreeModel::disconnectFromLayers( QgsLayerTreeGroup *parentGroup )
     997                 :            : {
     998                 :          0 :   const auto constChildren = parentGroup->children();
     999                 :          0 :   for ( QgsLayerTreeNode *node : constChildren )
    1000                 :            :   {
    1001                 :          0 :     if ( QgsLayerTree::isGroup( node ) )
    1002                 :          0 :       disconnectFromLayers( QgsLayerTree::toGroup( node ) );
    1003                 :          0 :     else if ( QgsLayerTree::isLayer( node ) )
    1004                 :          0 :       disconnectFromLayer( QgsLayerTree::toLayer( node ) );
    1005                 :            :   }
    1006                 :          0 : }
    1007                 :            : 
    1008                 :          0 : void QgsLayerTreeModel::connectToRootNode()
    1009                 :            : {
    1010                 :            :   Q_ASSERT( mRootNode );
    1011                 :            : 
    1012                 :          0 :   connect( mRootNode, &QgsLayerTreeNode::willAddChildren, this, &QgsLayerTreeModel::nodeWillAddChildren, Qt::ConnectionType::UniqueConnection );
    1013                 :          0 :   connect( mRootNode, &QgsLayerTreeNode::addedChildren, this, &QgsLayerTreeModel::nodeAddedChildren, Qt::ConnectionType::UniqueConnection );
    1014                 :          0 :   connect( mRootNode, &QgsLayerTreeNode::willRemoveChildren, this, &QgsLayerTreeModel::nodeWillRemoveChildren, Qt::ConnectionType::UniqueConnection );
    1015                 :          0 :   connect( mRootNode, &QgsLayerTreeNode::removedChildren, this, &QgsLayerTreeModel::nodeRemovedChildren, Qt::ConnectionType::UniqueConnection );
    1016                 :          0 :   connect( mRootNode, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeModel::nodeVisibilityChanged, Qt::ConnectionType::UniqueConnection );
    1017                 :          0 :   connect( mRootNode, &QgsLayerTreeNode::nameChanged, this, &QgsLayerTreeModel::nodeNameChanged, Qt::ConnectionType::UniqueConnection );
    1018                 :          0 :   connect( mRootNode, &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayerTreeModel::nodeCustomPropertyChanged, Qt::ConnectionType::UniqueConnection );
    1019                 :            : 
    1020                 :          0 :   connectToLayers( mRootNode );
    1021                 :          0 : }
    1022                 :            : 
    1023                 :          0 : void QgsLayerTreeModel::disconnectFromRootNode()
    1024                 :            : {
    1025                 :          0 :   disconnect( mRootNode, nullptr, this, nullptr );
    1026                 :            : 
    1027                 :          0 :   disconnectFromLayers( mRootNode );
    1028                 :          0 : }
    1029                 :            : 
    1030                 :          0 : void QgsLayerTreeModel::recursivelyEmitDataChanged( const QModelIndex &idx )
    1031                 :            : {
    1032                 :          0 :   QgsLayerTreeNode *node = index2node( idx );
    1033                 :          0 :   if ( !node )
    1034                 :          0 :     return;
    1035                 :            : 
    1036                 :          0 :   int count = node->children().count();
    1037                 :          0 :   if ( count == 0 )
    1038                 :          0 :     return;
    1039                 :          0 :   emit dataChanged( index( 0, 0, idx ), index( count - 1, 0, idx ) );
    1040                 :          0 :   for ( int i = 0; i < count; ++i )
    1041                 :          0 :     recursivelyEmitDataChanged( index( i, 0, idx ) );
    1042                 :          0 : }
    1043                 :            : 
    1044                 :          0 : void QgsLayerTreeModel::refreshScaleBasedLayers( const QModelIndex &idx, double previousScale )
    1045                 :            : {
    1046                 :          0 :   QgsLayerTreeNode *node = index2node( idx );
    1047                 :          0 :   if ( !node )
    1048                 :          0 :     return;
    1049                 :            : 
    1050                 :          0 :   if ( node->nodeType() == QgsLayerTreeNode::NodeLayer )
    1051                 :            :   {
    1052                 :          0 :     const QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
    1053                 :          0 :     if ( layer && layer->hasScaleBasedVisibility() )
    1054                 :            :     {
    1055                 :          0 :       if ( layer->isInScaleRange( mLegendMapViewScale ) != layer->isInScaleRange( previousScale ) )
    1056                 :          0 :         emit dataChanged( idx, idx, QVector<int>() << Qt::FontRole << Qt::ForegroundRole );
    1057                 :          0 :     }
    1058                 :          0 :   }
    1059                 :          0 :   int count = node->children().count();
    1060                 :          0 :   for ( int i = 0; i < count; ++i )
    1061                 :          0 :     refreshScaleBasedLayers( index( i, 0, idx ), previousScale );
    1062                 :          0 : }
    1063                 :            : 
    1064                 :          0 : Qt::DropActions QgsLayerTreeModel::supportedDropActions() const
    1065                 :            : {
    1066                 :          0 :   return Qt::CopyAction | Qt::MoveAction;
    1067                 :            : }
    1068                 :            : 
    1069                 :          0 : QStringList QgsLayerTreeModel::mimeTypes() const
    1070                 :            : {
    1071                 :          0 :   QStringList types;
    1072                 :          0 :   types << QStringLiteral( "application/qgis.layertreemodeldata" );
    1073                 :          0 :   return types;
    1074                 :          0 : }
    1075                 :            : 
    1076                 :            : 
    1077                 :          0 : QMimeData *QgsLayerTreeModel::mimeData( const QModelIndexList &indexes ) const
    1078                 :            : {
    1079                 :            :   // Sort the indexes. Depending on how the user selected the items, the indexes may be unsorted.
    1080                 :          0 :   QModelIndexList sortedIndexes = indexes;
    1081                 :          0 :   std::sort( sortedIndexes.begin(), sortedIndexes.end(), std::less<QModelIndex>() );
    1082                 :            : 
    1083                 :          0 :   QList<QgsLayerTreeNode *> nodesFinal = indexes2nodes( sortedIndexes, true );
    1084                 :            : 
    1085                 :          0 :   if ( nodesFinal.isEmpty() )
    1086                 :          0 :     return nullptr;
    1087                 :            : 
    1088                 :          0 :   QMimeData *mimeData = new QMimeData();
    1089                 :            : 
    1090                 :          0 :   QDomDocument layerTreeDoc;
    1091                 :          0 :   QDomElement rootLayerTreeElem = layerTreeDoc.createElement( QStringLiteral( "layer_tree_model_data" ) );
    1092                 :            : 
    1093                 :          0 :   for ( QgsLayerTreeNode *node : std::as_const( nodesFinal ) )
    1094                 :            :   {
    1095                 :          0 :     node->writeXml( rootLayerTreeElem, QgsReadWriteContext() );
    1096                 :            :   }
    1097                 :          0 :   layerTreeDoc.appendChild( rootLayerTreeElem );
    1098                 :            : 
    1099                 :          0 :   QString errorMessage;
    1100                 :          0 :   QgsReadWriteContext readWriteContext;
    1101                 :          0 :   QDomDocument layerDefinitionsDoc( QStringLiteral( "qgis-layer-definition" ) );
    1102                 :          0 :   QgsLayerDefinition::exportLayerDefinition( layerDefinitionsDoc, nodesFinal, errorMessage, QgsReadWriteContext() );
    1103                 :            : 
    1104                 :          0 :   QString txt = layerDefinitionsDoc.toString();
    1105                 :            : 
    1106                 :          0 :   mimeData->setData( QStringLiteral( "application/qgis.layertreemodeldata" ), layerTreeDoc.toString().toUtf8() );
    1107                 :          0 :   mimeData->setData( QStringLiteral( "application/qgis.application.pid" ), QString::number( QCoreApplication::applicationPid() ).toUtf8() );
    1108                 :          0 :   mimeData->setData( QStringLiteral( "application/qgis.layertree.layerdefinitions" ), txt.toUtf8() );
    1109                 :          0 :   mimeData->setData( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ), QgsMimeDataUtils::layerTreeNodesToUriList( nodesFinal ) );
    1110                 :            : 
    1111                 :          0 :   return mimeData;
    1112                 :          0 : }
    1113                 :            : 
    1114                 :          0 : bool QgsLayerTreeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
    1115                 :            : {
    1116                 :          0 :   if ( action == Qt::IgnoreAction )
    1117                 :          0 :     return true;
    1118                 :            : 
    1119                 :          0 :   if ( !data->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) )
    1120                 :          0 :     return false;
    1121                 :            : 
    1122                 :          0 :   if ( column >= columnCount( parent ) )
    1123                 :          0 :     return false;
    1124                 :            : 
    1125                 :          0 :   QgsLayerTreeNode *nodeParent = index2node( parent );
    1126                 :          0 :   if ( !QgsLayerTree::isGroup( nodeParent ) )
    1127                 :          0 :     return false;
    1128                 :            : 
    1129                 :          0 :   if ( parent.isValid() && row == -1 )
    1130                 :          0 :     row = 0; // if dropped directly onto group item, insert at first position
    1131                 :            : 
    1132                 :            :   // if we are coming from another QGIS instance, we need to add the layers too
    1133                 :          0 :   bool ok = false;
    1134                 :            :   // the application pid is only provided from QGIS 3.14, so do not check to OK before defaulting to moving in the legend
    1135                 :          0 :   qint64 qgisPid = data->data( QStringLiteral( "application/qgis.application.pid" ) ).toInt( &ok );
    1136                 :            : 
    1137                 :          0 :   if ( ok && qgisPid != QCoreApplication::applicationPid() )
    1138                 :            :   {
    1139                 :          0 :     QByteArray encodedLayerDefinitionData = data->data( QStringLiteral( "application/qgis.layertree.layerdefinitions" ) );
    1140                 :          0 :     QDomDocument layerDefinitionDoc;
    1141                 :          0 :     if ( !layerDefinitionDoc.setContent( QString::fromUtf8( encodedLayerDefinitionData ) ) )
    1142                 :          0 :       return false;
    1143                 :          0 :     QgsReadWriteContext context;
    1144                 :          0 :     QString errorMessage;
    1145                 :          0 :     QgsLayerDefinition::loadLayerDefinition( layerDefinitionDoc, QgsProject::instance(), QgsLayerTree::toGroup( nodeParent ), errorMessage, context );
    1146                 :          0 :     emit messageEmitted( tr( "New layers added from another QGIS instance" ) );
    1147                 :          0 :   }
    1148                 :            :   else
    1149                 :            :   {
    1150                 :          0 :     QByteArray encodedLayerTreeData = data->data( QStringLiteral( "application/qgis.layertreemodeldata" ) );
    1151                 :            : 
    1152                 :          0 :     QDomDocument layerTreeDoc;
    1153                 :          0 :     if ( !layerTreeDoc.setContent( QString::fromUtf8( encodedLayerTreeData ) ) )
    1154                 :          0 :       return false;
    1155                 :            : 
    1156                 :          0 :     QDomElement rootLayerTreeElem = layerTreeDoc.documentElement();
    1157                 :          0 :     if ( rootLayerTreeElem.tagName() != QLatin1String( "layer_tree_model_data" ) )
    1158                 :          0 :       return false;
    1159                 :            : 
    1160                 :          0 :     QList<QgsLayerTreeNode *> nodes;
    1161                 :            : 
    1162                 :          0 :     QDomElement elem = rootLayerTreeElem.firstChildElement();
    1163                 :          0 :     while ( !elem.isNull() )
    1164                 :            :     {
    1165                 :          0 :       QgsLayerTreeNode *node = QgsLayerTreeNode::readXml( elem, QgsProject::instance() );
    1166                 :          0 :       if ( node )
    1167                 :          0 :         nodes << node;
    1168                 :            : 
    1169                 :          0 :       elem = elem.nextSiblingElement();
    1170                 :            :     }
    1171                 :            : 
    1172                 :          0 :     if ( nodes.isEmpty() )
    1173                 :          0 :       return false;
    1174                 :            : 
    1175                 :          0 :     QgsLayerTree::toGroup( nodeParent )->insertChildNodes( row, nodes );
    1176                 :          0 :   }
    1177                 :          0 :   return true;
    1178                 :          0 : }
    1179                 :            : 
    1180                 :          0 : bool QgsLayerTreeModel::removeRows( int row, int count, const QModelIndex &parent )
    1181                 :            : {
    1182                 :          0 :   QgsLayerTreeNode *parentNode = index2node( parent );
    1183                 :          0 :   if ( QgsLayerTree::isGroup( parentNode ) )
    1184                 :            :   {
    1185                 :          0 :     QgsLayerTree::toGroup( parentNode )->removeChildren( row, count );
    1186                 :          0 :     return true;
    1187                 :            :   }
    1188                 :          0 :   return false;
    1189                 :          0 : }
    1190                 :            : 
    1191                 :          0 : void QgsLayerTreeModel::setFlags( QgsLayerTreeModel::Flags f )
    1192                 :            : {
    1193                 :          0 :   mFlags = f;
    1194                 :          0 : }
    1195                 :            : 
    1196                 :          0 : void QgsLayerTreeModel::setFlag( QgsLayerTreeModel::Flag f, bool on )
    1197                 :            : {
    1198                 :          0 :   if ( on )
    1199                 :          0 :     mFlags |= f;
    1200                 :            :   else
    1201                 :          0 :     mFlags &= ~f;
    1202                 :          0 : }
    1203                 :            : 
    1204                 :          0 : QgsLayerTreeModel::Flags QgsLayerTreeModel::flags() const
    1205                 :            : {
    1206                 :          0 :   return mFlags;
    1207                 :            : }
    1208                 :            : 
    1209                 :          0 : bool QgsLayerTreeModel::testFlag( QgsLayerTreeModel::Flag f ) const
    1210                 :            : {
    1211                 :          0 :   return mFlags.testFlag( f );
    1212                 :            : }
    1213                 :            : 
    1214                 :          0 : QIcon QgsLayerTreeModel::iconGroup()
    1215                 :            : {
    1216                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mActionFolder.svg" ) );
    1217                 :          0 : }
    1218                 :            : 
    1219                 :          0 : QList<QgsLayerTreeModelLegendNode *> QgsLayerTreeModel::filterLegendNodes( const QList<QgsLayerTreeModelLegendNode *> &nodes )
    1220                 :            : {
    1221                 :          0 :   QList<QgsLayerTreeModelLegendNode *> filtered;
    1222                 :            : 
    1223                 :          0 :   if ( mLegendFilterByScale > 0 )
    1224                 :            :   {
    1225                 :          0 :     for ( QgsLayerTreeModelLegendNode *node : std::as_const( nodes ) )
    1226                 :            :     {
    1227                 :          0 :       if ( node->isScaleOK( mLegendFilterByScale ) )
    1228                 :          0 :         filtered << node;
    1229                 :            :     }
    1230                 :          0 :   }
    1231                 :          0 :   else if ( mLegendFilterMapSettings )
    1232                 :            :   {
    1233                 :          0 :     if ( !nodes.isEmpty() && mLegendFilterMapSettings->layers().contains( nodes.at( 0 )->layerNode()->layer() ) )
    1234                 :            :     {
    1235                 :          0 :       for ( QgsLayerTreeModelLegendNode *node : std::as_const( nodes ) )
    1236                 :            :       {
    1237                 :          0 :         switch ( node->data( QgsSymbolLegendNode::NodeTypeRole ).value<QgsLayerTreeModelLegendNode::NodeTypes>() )
    1238                 :            :         {
    1239                 :            :           case QgsLayerTreeModelLegendNode::EmbeddedWidget:
    1240                 :          0 :             filtered << node;
    1241                 :          0 :             break;
    1242                 :            : 
    1243                 :            :           case QgsLayerTreeModelLegendNode::SimpleLegend:
    1244                 :            :           case QgsLayerTreeModelLegendNode::SymbolLegend:
    1245                 :            :           case QgsLayerTreeModelLegendNode::RasterSymbolLegend:
    1246                 :            :           case QgsLayerTreeModelLegendNode::ImageLegend:
    1247                 :            :           case QgsLayerTreeModelLegendNode::WmsLegend:
    1248                 :            :           case QgsLayerTreeModelLegendNode::DataDefinedSizeLegend:
    1249                 :            :           case QgsLayerTreeModelLegendNode::ColorRampLegend:
    1250                 :            :           {
    1251                 :          0 :             const QString ruleKey = node->data( QgsSymbolLegendNode::RuleKeyRole ).toString();
    1252                 :          0 :             bool checked = mLegendFilterUsesExtent || node->data( Qt::CheckStateRole ).toInt() == Qt::Checked;
    1253                 :          0 :             if ( checked )
    1254                 :            :             {
    1255                 :          0 :               if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( node->layerNode()->layer() ) )
    1256                 :            :               {
    1257                 :          0 :                 if ( mLegendFilterHitTest->legendKeyVisible( ruleKey, vl ) )
    1258                 :          0 :                   filtered << node;
    1259                 :          0 :               }
    1260                 :            :               else
    1261                 :            :               {
    1262                 :          0 :                 filtered << node;
    1263                 :            :               }
    1264                 :          0 :             }
    1265                 :            :             else  // unknown node type or unchecked
    1266                 :          0 :               filtered << node;
    1267                 :            :             break;
    1268                 :          0 :           }
    1269                 :            :         }
    1270                 :            :       }
    1271                 :          0 :     }
    1272                 :          0 :   }
    1273                 :            :   else
    1274                 :            :   {
    1275                 :          0 :     return nodes;
    1276                 :            :   }
    1277                 :            : 
    1278                 :          0 :   return filtered;
    1279                 :          0 : }
    1280                 :            : 
    1281                 :            : 
    1282                 :            : 
    1283                 :            : ///////////////////////////////////////////////////////////////////////////////
    1284                 :            : // Legend nodes routines - start
    1285                 :            : 
    1286                 :          0 : void QgsLayerTreeModel::legendCleanup()
    1287                 :            : {
    1288                 :          0 :   const auto constMLegend = mLegend;
    1289                 :          0 :   for ( const LayerLegendData &data : constMLegend )
    1290                 :            :   {
    1291                 :          0 :     qDeleteAll( data.originalNodes );
    1292                 :          0 :     delete data.tree;
    1293                 :            :   }
    1294                 :          0 :   mLegend.clear();
    1295                 :          0 : }
    1296                 :            : 
    1297                 :            : 
    1298                 :          0 : void QgsLayerTreeModel::removeLegendFromLayer( QgsLayerTreeLayer *nodeLayer )
    1299                 :            : {
    1300                 :          0 :   if ( mLegend.contains( nodeLayer ) )
    1301                 :            :   {
    1302                 :          0 :     qDeleteAll( mLegend[nodeLayer].originalNodes );
    1303                 :          0 :     delete mLegend[nodeLayer].tree;
    1304                 :          0 :     mLegend.remove( nodeLayer );
    1305                 :          0 :   }
    1306                 :          0 : }
    1307                 :            : 
    1308                 :            : 
    1309                 :          0 : void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer *nodeL )
    1310                 :            : {
    1311                 :          0 :   if ( !nodeL || !nodeL->layer() )
    1312                 :          0 :     return;
    1313                 :            : 
    1314                 :          0 :   QgsMapLayer *ml = nodeL->layer();
    1315                 :            : 
    1316                 :          0 :   QgsMapLayerStyleOverride styleOverride( ml );
    1317                 :          0 :   if ( mLayerStyleOverrides.contains( ml->id() ) )
    1318                 :          0 :     styleOverride.setOverrideStyle( mLayerStyleOverrides.value( ml->id() ) );
    1319                 :            : 
    1320                 :          0 :   QgsMapLayerLegend *layerLegend = ml->legend();
    1321                 :          0 :   if ( !layerLegend )
    1322                 :          0 :     return;
    1323                 :          0 :   QList<QgsLayerTreeModelLegendNode *> lstNew = layerLegend->createLayerTreeModelLegendNodes( nodeL );
    1324                 :            : 
    1325                 :            :   // apply filtering defined in layer node's custom properties (reordering, filtering, custom labels)
    1326                 :          0 :   QgsMapLayerLegendUtils::applyLayerNodeProperties( nodeL, lstNew );
    1327                 :            : 
    1328                 :          0 :   if ( testFlag( UseEmbeddedWidgets ) )
    1329                 :            :   {
    1330                 :            :     // generate placeholder legend nodes that will be replaced by widgets in QgsLayerTreeView
    1331                 :          0 :     int widgetsCount = ml->customProperty( QStringLiteral( "embeddedWidgets/count" ), 0 ).toInt();
    1332                 :          0 :     while ( widgetsCount > 0 )
    1333                 :            :     {
    1334                 :          0 :       lstNew.insert( 0, new EmbeddedWidgetLegendNode( nodeL ) );
    1335                 :          0 :       --widgetsCount;
    1336                 :            :     }
    1337                 :          0 :   }
    1338                 :            : 
    1339                 :          0 :   QList<QgsLayerTreeModelLegendNode *> filteredLstNew = filterLegendNodes( lstNew );
    1340                 :            : 
    1341                 :          0 :   const auto constLstNew = lstNew;
    1342                 :          0 :   for ( QgsLayerTreeModelLegendNode *n : constLstNew )
    1343                 :            :   {
    1344                 :          0 :     n->setParent( this );
    1345                 :          0 :     connect( n, &QgsLayerTreeModelLegendNode::dataChanged, this, &QgsLayerTreeModel::legendNodeDataChanged );
    1346                 :          0 :     connect( n, &QgsLayerTreeModelLegendNode::sizeChanged, this, &QgsLayerTreeModel::legendNodeSizeChanged );
    1347                 :            :   }
    1348                 :            : 
    1349                 :            :   // See if we have an embedded node - if we do, we will not use it among active nodes.
    1350                 :            :   // Legend node embedded in parent does not have to be the first one,
    1351                 :            :   // there can be also nodes generated for embedded widgets
    1352                 :          0 :   QgsLayerTreeModelLegendNode *embeddedNode = nullptr;
    1353                 :          0 :   const auto constFilteredLstNew = filteredLstNew;
    1354                 :          0 :   for ( QgsLayerTreeModelLegendNode *legendNode : constFilteredLstNew )
    1355                 :            :   {
    1356                 :          0 :     if ( legendNode->isEmbeddedInParent() )
    1357                 :            :     {
    1358                 :          0 :       embeddedNode = legendNode;
    1359                 :          0 :       filteredLstNew.removeOne( legendNode );
    1360                 :          0 :       break;
    1361                 :            :     }
    1362                 :            :   }
    1363                 :            : 
    1364                 :          0 :   LayerLegendTree *legendTree = nullptr;
    1365                 :            : 
    1366                 :            :   // maybe the legend nodes form a tree - try to create a tree structure from the list
    1367                 :          0 :   if ( testFlag( ShowLegendAsTree ) )
    1368                 :          0 :     legendTree = tryBuildLegendTree( filteredLstNew );
    1369                 :            : 
    1370                 :          0 :   int count = legendTree ? legendTree->children[nullptr].count() : filteredLstNew.count();
    1371                 :            : 
    1372                 :          0 :   if ( !filteredLstNew.isEmpty() )
    1373                 :            :   {
    1374                 :            :     // Make sure it's clear
    1375                 :          0 :     const QModelIndex nodeIndex { node2index( nodeL ) };
    1376                 :          0 :     if ( rowCount( nodeIndex ) > 0 )
    1377                 :            :     {
    1378                 :          0 :       beginRemoveRows( node2index( nodeL ), 0, rowCount( nodeIndex ) - 1 );
    1379                 :          0 :       mLegend[nodeL] = LayerLegendData();
    1380                 :          0 :       endRemoveRows();
    1381                 :          0 :     }
    1382                 :          0 :     beginInsertRows( node2index( nodeL ), 0, count - 1 );
    1383                 :          0 :   }
    1384                 :            : 
    1385                 :          0 :   LayerLegendData data;
    1386                 :          0 :   data.originalNodes = lstNew;
    1387                 :          0 :   data.activeNodes = filteredLstNew;
    1388                 :          0 :   data.embeddedNodeInParent = embeddedNode;
    1389                 :          0 :   data.tree = legendTree;
    1390                 :            : 
    1391                 :          0 :   mLegend[nodeL] = data;
    1392                 :            : 
    1393                 :          0 :   if ( !filteredLstNew.isEmpty() )
    1394                 :            :   {
    1395                 :          0 :     endInsertRows();
    1396                 :          0 :   }
    1397                 :            : 
    1398                 :            :   // invalidate map based data even if the data is not map-based to make sure
    1399                 :            :   // the symbol sizes are computed at least once
    1400                 :          0 :   mInvalidatedNodes.insert( nodeL );
    1401                 :          0 :   legendInvalidateMapBasedData();
    1402                 :          0 : }
    1403                 :            : 
    1404                 :            : 
    1405                 :          0 : QgsLayerTreeModel::LayerLegendTree *QgsLayerTreeModel::tryBuildLegendTree( const QList<QgsLayerTreeModelLegendNode *> &nodes )
    1406                 :            : {
    1407                 :            :   // first check whether there are any legend nodes that are not top-level
    1408                 :          0 :   bool hasParentKeys = false;
    1409                 :          0 :   for ( QgsLayerTreeModelLegendNode *n : nodes )
    1410                 :            :   {
    1411                 :          0 :     if ( !n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString().isEmpty() )
    1412                 :            :     {
    1413                 :          0 :       hasParentKeys = true;
    1414                 :          0 :       break;
    1415                 :            :     }
    1416                 :            :   }
    1417                 :          0 :   if ( !hasParentKeys )
    1418                 :          0 :     return nullptr; // all legend nodes are top-level => stick with list representation
    1419                 :            : 
    1420                 :            :   // make mapping from rules to nodes and do some sanity checks
    1421                 :          0 :   QHash<QString, QgsLayerTreeModelLegendNode *> rule2node;
    1422                 :          0 :   rule2node[QString()] = nullptr;
    1423                 :          0 :   for ( QgsLayerTreeModelLegendNode *n : nodes )
    1424                 :            :   {
    1425                 :          0 :     QString ruleKey = n->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
    1426                 :          0 :     if ( ruleKey.isEmpty() ) // in tree all nodes must have key
    1427                 :          0 :       return nullptr;
    1428                 :          0 :     if ( rule2node.contains( ruleKey ) ) // and they must be unique
    1429                 :          0 :       return nullptr;
    1430                 :          0 :     rule2node[ruleKey] = n;
    1431                 :          0 :   }
    1432                 :            : 
    1433                 :            :   // create the tree structure
    1434                 :          0 :   LayerLegendTree *tree = new LayerLegendTree;
    1435                 :          0 :   for ( QgsLayerTreeModelLegendNode *n : nodes )
    1436                 :            :   {
    1437                 :          0 :     QString parentRuleKey = n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString();
    1438                 :          0 :     QgsLayerTreeModelLegendNode *parent = rule2node.value( parentRuleKey, nullptr );
    1439                 :          0 :     tree->parents[n] = parent;
    1440                 :          0 :     tree->children[parent] << n;
    1441                 :          0 :   }
    1442                 :          0 :   return tree;
    1443                 :          0 : }
    1444                 :            : 
    1445                 :          0 : QgsRenderContext *QgsLayerTreeModel::createTemporaryRenderContext() const
    1446                 :            : {
    1447                 :          0 :   double scale = 0.0;
    1448                 :          0 :   double mupp = 0.0;
    1449                 :          0 :   int dpi = 0;
    1450                 :          0 :   legendMapViewData( &mupp, &dpi, &scale );
    1451                 :          0 :   bool validData = !qgsDoubleNear( mupp, 0.0 ) && dpi != 0 && !qgsDoubleNear( scale, 0.0 );
    1452                 :            : 
    1453                 :            :   // setup temporary render context
    1454                 :          0 :   std::unique_ptr<QgsRenderContext> context( new QgsRenderContext );
    1455                 :          0 :   context->setScaleFactor( dpi / 25.4 );
    1456                 :          0 :   context->setRendererScale( scale );
    1457                 :          0 :   context->setMapToPixel( QgsMapToPixel( mupp ) );
    1458                 :          0 :   context->setFlag( QgsRenderContext::RenderSymbolPreview );
    1459                 :          0 :   return validData ? context.release() : nullptr;
    1460                 :          0 : }
    1461                 :            : 
    1462                 :            : 
    1463                 :          0 : QgsLayerTreeModelLegendNode *QgsLayerTreeModel::index2legendNode( const QModelIndex &index )
    1464                 :            : {
    1465                 :          0 :   return qobject_cast<QgsLayerTreeModelLegendNode *>( reinterpret_cast<QObject *>( index.internalPointer() ) );
    1466                 :            : }
    1467                 :            : 
    1468                 :            : 
    1469                 :          0 : QModelIndex QgsLayerTreeModel::legendNode2index( QgsLayerTreeModelLegendNode *legendNode )
    1470                 :            : {
    1471                 :          0 :   const LayerLegendData &data = mLegend[legendNode->layerNode()];
    1472                 :          0 :   if ( data.tree )
    1473                 :            :   {
    1474                 :          0 :     if ( QgsLayerTreeModelLegendNode *parentLegendNode = data.tree->parents[legendNode] )
    1475                 :            :     {
    1476                 :          0 :       QModelIndex parentIndex = legendNode2index( parentLegendNode );
    1477                 :          0 :       int row = data.tree->children[parentLegendNode].indexOf( legendNode );
    1478                 :          0 :       return index( row, 0, parentIndex );
    1479                 :            :     }
    1480                 :            :     else
    1481                 :            :     {
    1482                 :          0 :       QModelIndex parentIndex = node2index( legendNode->layerNode() );
    1483                 :          0 :       int row = data.tree->children[nullptr].indexOf( legendNode );
    1484                 :          0 :       return index( row, 0, parentIndex );
    1485                 :            :     }
    1486                 :            :   }
    1487                 :            : 
    1488                 :          0 :   QModelIndex parentIndex = node2index( legendNode->layerNode() );
    1489                 :            :   Q_ASSERT( parentIndex.isValid() );
    1490                 :          0 :   int row = data.activeNodes.indexOf( legendNode );
    1491                 :          0 :   if ( row < 0 ) // legend node may be filtered (exists within the list of original nodes, but not in active nodes)
    1492                 :          0 :     return QModelIndex();
    1493                 :            : 
    1494                 :          0 :   return index( row, 0, parentIndex );
    1495                 :          0 : }
    1496                 :            : 
    1497                 :            : 
    1498                 :          0 : int QgsLayerTreeModel::legendNodeRowCount( QgsLayerTreeModelLegendNode *node ) const
    1499                 :            : {
    1500                 :          0 :   const LayerLegendData &data = mLegend[node->layerNode()];
    1501                 :          0 :   if ( data.tree )
    1502                 :          0 :     return data.tree->children[node].count();
    1503                 :            : 
    1504                 :          0 :   return 0; // they are leaves
    1505                 :          0 : }
    1506                 :            : 
    1507                 :            : 
    1508                 :          0 : int QgsLayerTreeModel::legendRootRowCount( QgsLayerTreeLayer *nL ) const
    1509                 :            : {
    1510                 :          0 :   if ( !mLegend.contains( nL ) )
    1511                 :          0 :     return 0;
    1512                 :            : 
    1513                 :          0 :   const LayerLegendData &data = mLegend[nL];
    1514                 :          0 :   if ( data.tree )
    1515                 :          0 :     return data.tree->children[nullptr].count();
    1516                 :            : 
    1517                 :          0 :   int count = data.activeNodes.count();
    1518                 :          0 :   return count;
    1519                 :          0 : }
    1520                 :            : 
    1521                 :            : 
    1522                 :          0 : QModelIndex QgsLayerTreeModel::legendRootIndex( int row, int column, QgsLayerTreeLayer *nL ) const
    1523                 :            : {
    1524                 :            :   Q_ASSERT( mLegend.contains( nL ) );
    1525                 :          0 :   const LayerLegendData &data = mLegend[nL];
    1526                 :          0 :   if ( data.tree )
    1527                 :          0 :     return createIndex( row, column, static_cast<QObject *>( data.tree->children[nullptr].at( row ) ) );
    1528                 :            : 
    1529                 :          0 :   return createIndex( row, column, static_cast<QObject *>( data.activeNodes.at( row ) ) );
    1530                 :          0 : }
    1531                 :            : 
    1532                 :            : 
    1533                 :          0 : QModelIndex QgsLayerTreeModel::legendNodeIndex( int row, int column, QgsLayerTreeModelLegendNode *node ) const
    1534                 :            : {
    1535                 :          0 :   const LayerLegendData &data = mLegend[node->layerNode()];
    1536                 :          0 :   if ( data.tree )
    1537                 :          0 :     return createIndex( row, column, static_cast<QObject *>( data.tree->children[node].at( row ) ) );
    1538                 :            : 
    1539                 :          0 :   return QModelIndex(); // have no children
    1540                 :          0 : }
    1541                 :            : 
    1542                 :            : 
    1543                 :          0 : QModelIndex QgsLayerTreeModel::legendParent( QgsLayerTreeModelLegendNode *legendNode ) const
    1544                 :            : {
    1545                 :          0 :   QgsLayerTreeLayer *layerNode = legendNode->layerNode();
    1546                 :          0 :   const LayerLegendData &data = mLegend[layerNode];
    1547                 :          0 :   if ( data.tree )
    1548                 :            :   {
    1549                 :          0 :     if ( QgsLayerTreeModelLegendNode *parentNode = data.tree->parents[legendNode] )
    1550                 :            :     {
    1551                 :          0 :       QgsLayerTreeModelLegendNode *grandParentNode = data.tree->parents[parentNode]; // may be null (not a problem)
    1552                 :          0 :       int row = data.tree->children[grandParentNode].indexOf( parentNode );
    1553                 :          0 :       return createIndex( row, 0, static_cast<QObject *>( parentNode ) );
    1554                 :            :     }
    1555                 :            :     else
    1556                 :          0 :       return indexOfParentLayerTreeNode( layerNode );
    1557                 :            :   }
    1558                 :            : 
    1559                 :          0 :   return indexOfParentLayerTreeNode( layerNode );
    1560                 :          0 : }
    1561                 :            : 
    1562                 :            : 
    1563                 :          0 : QVariant QgsLayerTreeModel::legendNodeData( QgsLayerTreeModelLegendNode *node, int role ) const
    1564                 :            : {
    1565                 :          0 :   if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
    1566                 :          0 :     return QVariant();
    1567                 :          0 :   return node->data( role );
    1568                 :          0 : }
    1569                 :            : 
    1570                 :            : 
    1571                 :          0 : Qt::ItemFlags QgsLayerTreeModel::legendNodeFlags( QgsLayerTreeModelLegendNode *node ) const
    1572                 :            : {
    1573                 :          0 :   Qt::ItemFlags f = node->flags();
    1574                 :          0 :   if ( !testFlag( AllowLegendChangeState ) )
    1575                 :          0 :     f &= ~Qt::ItemIsUserCheckable;
    1576                 :          0 :   return f;
    1577                 :            : }
    1578                 :            : 
    1579                 :            : 
    1580                 :          0 : bool QgsLayerTreeModel::legendEmbeddedInParent( QgsLayerTreeLayer *nodeLayer ) const
    1581                 :            : {
    1582                 :          0 :   return static_cast< bool >( mLegend[nodeLayer].embeddedNodeInParent );
    1583                 :            : }
    1584                 :            : 
    1585                 :          0 : QgsLayerTreeModelLegendNode *QgsLayerTreeModel::legendNodeEmbeddedInParent( QgsLayerTreeLayer *nodeLayer ) const
    1586                 :            : {
    1587                 :          0 :   return mLegend[nodeLayer].embeddedNodeInParent;
    1588                 :            : }
    1589                 :            : 
    1590                 :            : 
    1591                 :          0 : QIcon QgsLayerTreeModel::legendIconEmbeddedInParent( QgsLayerTreeLayer *nodeLayer ) const
    1592                 :            : {
    1593                 :          0 :   QgsLayerTreeModelLegendNode *legendNode = mLegend[nodeLayer].embeddedNodeInParent;
    1594                 :          0 :   if ( !legendNode )
    1595                 :          0 :     return QIcon();
    1596                 :          0 :   return QIcon( qvariant_cast<QPixmap>( legendNode->data( Qt::DecorationRole ) ) );
    1597                 :          0 : }
    1598                 :            : 
    1599                 :            : 
    1600                 :          0 : QList<QgsLayerTreeModelLegendNode *> QgsLayerTreeModel::layerLegendNodes( QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent )
    1601                 :            : {
    1602                 :          0 :   if ( !mLegend.contains( nodeLayer ) )
    1603                 :          0 :     return QList<QgsLayerTreeModelLegendNode *>();
    1604                 :            : 
    1605                 :          0 :   const LayerLegendData &data = mLegend[nodeLayer];
    1606                 :          0 :   QList<QgsLayerTreeModelLegendNode *> lst( data.activeNodes );
    1607                 :          0 :   if ( !skipNodeEmbeddedInParent && data.embeddedNodeInParent )
    1608                 :          0 :     lst.prepend( data.embeddedNodeInParent );
    1609                 :          0 :   return lst;
    1610                 :          0 : }
    1611                 :            : 
    1612                 :          0 : QList<QgsLayerTreeModelLegendNode *> QgsLayerTreeModel::layerOriginalLegendNodes( QgsLayerTreeLayer *nodeLayer )
    1613                 :            : {
    1614                 :          0 :   return mLegend.value( nodeLayer ).originalNodes;
    1615                 :          0 : }
    1616                 :            : 
    1617                 :          0 : QgsLayerTreeModelLegendNode *QgsLayerTreeModel::findLegendNode( const QString &layerId, const QString &ruleKey ) const
    1618                 :            : {
    1619                 :          0 :   for ( auto it = mLegend.constBegin(); it != mLegend.constEnd(); ++it )
    1620                 :            :   {
    1621                 :          0 :     QgsLayerTreeLayer *layer = it.key();
    1622                 :          0 :     if ( layer->layerId() == layerId )
    1623                 :            :     {
    1624                 :          0 :       const auto activeNodes = mLegend.value( layer ).activeNodes;
    1625                 :          0 :       for ( QgsLayerTreeModelLegendNode *legendNode : activeNodes )
    1626                 :            :       {
    1627                 :          0 :         if ( legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() == ruleKey )
    1628                 :            :         {
    1629                 :            :           //found it!
    1630                 :          0 :           return legendNode;
    1631                 :            :         }
    1632                 :            :       }
    1633                 :          0 :     }
    1634                 :          0 :   }
    1635                 :            : 
    1636                 :          0 :   return nullptr;
    1637                 :          0 : }
    1638                 :            : 
    1639                 :          0 : void QgsLayerTreeModel::legendInvalidateMapBasedData()
    1640                 :            : {
    1641                 :          0 :   if ( !testFlag( DeferredLegendInvalidation ) )
    1642                 :          0 :     invalidateLegendMapBasedData();
    1643                 :            :   else
    1644                 :          0 :     mDeferLegendInvalidationTimer.start( 10 );
    1645                 :          0 : }
    1646                 :            : 
    1647                 :          0 : void QgsLayerTreeModel::invalidateLegendMapBasedData()
    1648                 :            : {
    1649                 :            :   // we have varying icon sizes, and we want icon to be centered and
    1650                 :            :   // text to be left aligned, so we have to compute the max width of icons
    1651                 :            :   //
    1652                 :            :   // we do that for nodes which share a common parent
    1653                 :            :   //
    1654                 :            :   // we do that here because for symbols with size defined in map units
    1655                 :            :   // the symbol sizes changes depends on the zoom level
    1656                 :            : 
    1657                 :          0 :   std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
    1658                 :            : 
    1659                 :          0 :   for ( QgsLayerTreeLayer *layerNode : std::as_const( mInvalidatedNodes ) )
    1660                 :            :   {
    1661                 :          0 :     const LayerLegendData &data = mLegend.value( layerNode );
    1662                 :            : 
    1663                 :          0 :     QList<QgsSymbolLegendNode *> symbolNodes;
    1664                 :          0 :     QMap<QString, int> widthMax;
    1665                 :          0 :     for ( QgsLayerTreeModelLegendNode *legendNode : std::as_const( data.originalNodes ) )
    1666                 :            :     {
    1667                 :          0 :       QgsSymbolLegendNode *n = qobject_cast<QgsSymbolLegendNode *>( legendNode );
    1668                 :          0 :       if ( n )
    1669                 :            :       {
    1670                 :          0 :         const QSize sz( n->minimumIconSize( context.get() ) );
    1671                 :          0 :         const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() );
    1672                 :          0 :         widthMax[parentKey] = std::max( sz.width(), widthMax.contains( parentKey ) ? widthMax[parentKey] : 0 );
    1673                 :          0 :         n->setIconSize( sz );
    1674                 :          0 :         symbolNodes.append( n );
    1675                 :          0 :       }
    1676                 :            :     }
    1677                 :          0 :     for ( QgsSymbolLegendNode *n : std::as_const( symbolNodes ) )
    1678                 :            :     {
    1679                 :          0 :       const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() );
    1680                 :            :       Q_ASSERT( widthMax[parentKey] > 0 );
    1681                 :          0 :       const int twiceMarginWidth = 2; // a one pixel margin avoids hugly rendering of icon
    1682                 :          0 :       n->setIconSize( QSize( widthMax[parentKey] + twiceMarginWidth, n->iconSize().rheight() + twiceMarginWidth ) );
    1683                 :          0 :     }
    1684                 :          0 :     for ( QgsLayerTreeModelLegendNode *legendNode : std::as_const( data.originalNodes ) )
    1685                 :          0 :       legendNode->invalidateMapBasedData();
    1686                 :          0 :   }
    1687                 :            : 
    1688                 :          0 :   mInvalidatedNodes.clear();
    1689                 :          0 : }
    1690                 :            : 
    1691                 :            : // Legend nodes routines - end
    1692                 :            : ///////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.14