LCOV - code coverage report
Current view: top level - core/layout - qgslayoutitemattributetable.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 505 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgslayoutitemattributetable.cpp
       3                 :            :                          -------------------------------
       4                 :            :     begin                : November 2017
       5                 :            :     copyright            : (C) 2017 by Nyall Dawson
       6                 :            :     email                : nyall dot dawson at gmail dot com
       7                 :            :  ***************************************************************************/
       8                 :            : 
       9                 :            : /***************************************************************************
      10                 :            :  *                                                                         *
      11                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      12                 :            :  *   it under the terms of the GNU General Public License as published by  *
      13                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      14                 :            :  *   (at your option) any later version.                                   *
      15                 :            :  *                                                                         *
      16                 :            :  ***************************************************************************/
      17                 :            : 
      18                 :            : #include "qgslayoutitemattributetable.h"
      19                 :            : #include "qgslayout.h"
      20                 :            : #include "qgslayouttablecolumn.h"
      21                 :            : #include "qgslayoutitemmap.h"
      22                 :            : #include "qgslayoututils.h"
      23                 :            : #include "qgsfeatureiterator.h"
      24                 :            : #include "qgsvectorlayer.h"
      25                 :            : #include "qgslayoutframe.h"
      26                 :            : #include "qgsproject.h"
      27                 :            : #include "qgsrelationmanager.h"
      28                 :            : #include "qgsgeometry.h"
      29                 :            : #include "qgsexception.h"
      30                 :            : #include "qgsmapsettings.h"
      31                 :            : #include "qgsexpressioncontextutils.h"
      32                 :            : #include "qgsexpressionnodeimpl.h"
      33                 :            : #include "qgsgeometryengine.h"
      34                 :            : #include "qgsconditionalstyle.h"
      35                 :            : 
      36                 :            : //
      37                 :            : // QgsLayoutItemAttributeTable
      38                 :            : //
      39                 :            : 
      40                 :          0 : QgsLayoutItemAttributeTable::QgsLayoutItemAttributeTable( QgsLayout *layout )
      41                 :          0 :   : QgsLayoutTable( layout )
      42                 :          0 : {
      43                 :          0 :   if ( mLayout )
      44                 :            :   {
      45                 :          0 :     connect( mLayout->project(), static_cast < void ( QgsProject::* )( const QString & ) >( &QgsProject::layerWillBeRemoved ), this, &QgsLayoutItemAttributeTable::removeLayer );
      46                 :            : 
      47                 :            :     //coverage layer change = regenerate columns
      48                 :          0 :     connect( &mLayout->reportContext(), &QgsLayoutReportContext::layerChanged, this, &QgsLayoutItemAttributeTable::atlasLayerChanged );
      49                 :          0 :   }
      50                 :          0 :   refreshAttributes();
      51                 :          0 : }
      52                 :            : 
      53                 :          0 : int QgsLayoutItemAttributeTable::type() const
      54                 :            : {
      55                 :          0 :   return QgsLayoutItemRegistry::LayoutAttributeTable;
      56                 :            : }
      57                 :            : 
      58                 :          0 : QIcon QgsLayoutItemAttributeTable::icon() const
      59                 :            : {
      60                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemTable.svg" ) );
      61                 :          0 : }
      62                 :            : 
      63                 :          0 : QgsLayoutItemAttributeTable *QgsLayoutItemAttributeTable::create( QgsLayout *layout )
      64                 :            : {
      65                 :          0 :   return new QgsLayoutItemAttributeTable( layout );
      66                 :          0 : }
      67                 :            : 
      68                 :          0 : QString QgsLayoutItemAttributeTable::displayName() const
      69                 :            : {
      70                 :          0 :   return tr( "<Attribute table frame>" );
      71                 :            : }
      72                 :            : 
      73                 :          0 : void QgsLayoutItemAttributeTable::setVectorLayer( QgsVectorLayer *layer )
      74                 :            : {
      75                 :          0 :   if ( layer == mVectorLayer.get() )
      76                 :            :   {
      77                 :            :     //no change
      78                 :          0 :     return;
      79                 :            :   }
      80                 :            : 
      81                 :          0 :   QgsVectorLayer *prevLayer = sourceLayer();
      82                 :          0 :   mVectorLayer.setLayer( layer );
      83                 :            : 
      84                 :          0 :   if ( mSource == QgsLayoutItemAttributeTable::LayerAttributes && layer != prevLayer )
      85                 :            :   {
      86                 :          0 :     if ( prevLayer )
      87                 :            :     {
      88                 :            :       //disconnect from previous layer
      89                 :          0 :       disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
      90                 :          0 :     }
      91                 :            : 
      92                 :            :     //rebuild column list to match all columns from layer
      93                 :          0 :     resetColumns();
      94                 :            : 
      95                 :            :     //listen for modifications to layer and refresh table when they occur
      96                 :          0 :     connect( mVectorLayer.get(), &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
      97                 :          0 :   }
      98                 :            : 
      99                 :          0 :   refreshAttributes();
     100                 :          0 :   emit changed();
     101                 :          0 : }
     102                 :            : 
     103                 :          0 : void QgsLayoutItemAttributeTable::setRelationId( const QString &relationId )
     104                 :            : {
     105                 :          0 :   if ( relationId == mRelationId )
     106                 :            :   {
     107                 :            :     //no change
     108                 :          0 :     return;
     109                 :            :   }
     110                 :            : 
     111                 :          0 :   QgsVectorLayer *prevLayer = sourceLayer();
     112                 :          0 :   mRelationId = relationId;
     113                 :          0 :   QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
     114                 :          0 :   QgsVectorLayer *newLayer = relation.referencingLayer();
     115                 :            : 
     116                 :          0 :   if ( mSource == QgsLayoutItemAttributeTable::RelationChildren && newLayer != prevLayer )
     117                 :            :   {
     118                 :          0 :     if ( prevLayer )
     119                 :            :     {
     120                 :            :       //disconnect from previous layer
     121                 :          0 :       disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
     122                 :          0 :     }
     123                 :            : 
     124                 :            :     //rebuild column list to match all columns from layer
     125                 :          0 :     resetColumns();
     126                 :            : 
     127                 :            :     //listen for modifications to layer and refresh table when they occur
     128                 :          0 :     connect( newLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
     129                 :          0 :   }
     130                 :            : 
     131                 :          0 :   refreshAttributes();
     132                 :          0 :   emit changed();
     133                 :          0 : }
     134                 :            : 
     135                 :          0 : void QgsLayoutItemAttributeTable::atlasLayerChanged( QgsVectorLayer *layer )
     136                 :            : {
     137                 :          0 :   if ( mSource != QgsLayoutItemAttributeTable::AtlasFeature || layer == mCurrentAtlasLayer )
     138                 :            :   {
     139                 :            :     //nothing to do
     140                 :          0 :     return;
     141                 :            :   }
     142                 :            : 
     143                 :            :   //atlas feature mode, atlas layer changed, so we need to reset columns
     144                 :          0 :   if ( mCurrentAtlasLayer )
     145                 :            :   {
     146                 :            :     //disconnect from previous layer
     147                 :          0 :     disconnect( mCurrentAtlasLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
     148                 :          0 :   }
     149                 :            : 
     150                 :          0 :   const bool mustRebuildColumns = static_cast< bool >( mCurrentAtlasLayer ) || mColumns.empty();
     151                 :          0 :   mCurrentAtlasLayer = layer;
     152                 :            : 
     153                 :          0 :   if ( mustRebuildColumns )
     154                 :            :   {
     155                 :            :     //rebuild column list to match all columns from layer
     156                 :          0 :     resetColumns();
     157                 :          0 :   }
     158                 :            : 
     159                 :          0 :   refreshAttributes();
     160                 :            : 
     161                 :            :   //listen for modifications to layer and refresh table when they occur
     162                 :          0 :   connect( layer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
     163                 :          0 : }
     164                 :            : 
     165                 :          0 : void QgsLayoutItemAttributeTable::resetColumns()
     166                 :            : {
     167                 :          0 :   QgsVectorLayer *source = sourceLayer();
     168                 :          0 :   if ( !source )
     169                 :            :   {
     170                 :          0 :     return;
     171                 :            :   }
     172                 :            : 
     173                 :            :   //remove existing columns
     174                 :          0 :   mColumns.clear();
     175                 :          0 :   mSortColumns.clear();
     176                 :            : 
     177                 :            :   //rebuild columns list from vector layer fields
     178                 :          0 :   int idx = 0;
     179                 :          0 :   const QgsFields sourceFields = source->fields();
     180                 :            : 
     181                 :          0 :   for ( const auto &field : sourceFields )
     182                 :            :   {
     183                 :          0 :     QString currentAlias = source->attributeDisplayName( idx );
     184                 :          0 :     QgsLayoutTableColumn col;
     185                 :          0 :     col.setAttribute( field.name() );
     186                 :          0 :     col.setHeading( currentAlias );
     187                 :          0 :     mColumns.append( col );
     188                 :          0 :     idx++;
     189                 :          0 :   }
     190                 :          0 : }
     191                 :            : 
     192                 :          0 : void QgsLayoutItemAttributeTable::disconnectCurrentMap()
     193                 :            : {
     194                 :          0 :   if ( !mMap )
     195                 :            :   {
     196                 :          0 :     return;
     197                 :            :   }
     198                 :            : 
     199                 :          0 :   disconnect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutTable::refreshAttributes );
     200                 :          0 :   disconnect( mMap, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutTable::refreshAttributes );
     201                 :          0 :   disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemAttributeTable::disconnectCurrentMap );
     202                 :          0 :   mMap = nullptr;
     203                 :          0 : }
     204                 :            : 
     205                 :          0 : bool QgsLayoutItemAttributeTable::useConditionalStyling() const
     206                 :            : {
     207                 :          0 :   return mUseConditionalStyling;
     208                 :            : }
     209                 :            : 
     210                 :          0 : void QgsLayoutItemAttributeTable::setUseConditionalStyling( bool useConditionalStyling )
     211                 :            : {
     212                 :          0 :   if ( useConditionalStyling == mUseConditionalStyling )
     213                 :            :   {
     214                 :          0 :     return;
     215                 :            :   }
     216                 :            : 
     217                 :          0 :   mUseConditionalStyling = useConditionalStyling;
     218                 :          0 :   refreshAttributes();
     219                 :          0 :   emit changed();
     220                 :          0 : }
     221                 :            : 
     222                 :          0 : void QgsLayoutItemAttributeTable::setMap( QgsLayoutItemMap *map )
     223                 :            : {
     224                 :          0 :   if ( map == mMap )
     225                 :            :   {
     226                 :            :     //no change
     227                 :          0 :     return;
     228                 :            :   }
     229                 :          0 :   disconnectCurrentMap();
     230                 :            : 
     231                 :          0 :   mMap = map;
     232                 :          0 :   if ( mMap )
     233                 :            :   {
     234                 :            :     //listen out for extent changes in linked map
     235                 :          0 :     connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutTable::refreshAttributes );
     236                 :          0 :     connect( mMap, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutTable::refreshAttributes );
     237                 :          0 :     connect( mMap, &QObject::destroyed, this, &QgsLayoutItemAttributeTable::disconnectCurrentMap );
     238                 :          0 :   }
     239                 :          0 :   refreshAttributes();
     240                 :          0 :   emit changed();
     241                 :          0 : }
     242                 :            : 
     243                 :          0 : void QgsLayoutItemAttributeTable::setMaximumNumberOfFeatures( const int features )
     244                 :            : {
     245                 :          0 :   if ( features == mMaximumNumberOfFeatures )
     246                 :            :   {
     247                 :          0 :     return;
     248                 :            :   }
     249                 :            : 
     250                 :          0 :   mMaximumNumberOfFeatures = features;
     251                 :          0 :   refreshAttributes();
     252                 :          0 :   emit changed();
     253                 :          0 : }
     254                 :            : 
     255                 :          0 : void QgsLayoutItemAttributeTable::setUniqueRowsOnly( const bool uniqueOnly )
     256                 :            : {
     257                 :          0 :   if ( uniqueOnly == mShowUniqueRowsOnly )
     258                 :            :   {
     259                 :          0 :     return;
     260                 :            :   }
     261                 :            : 
     262                 :          0 :   mShowUniqueRowsOnly = uniqueOnly;
     263                 :          0 :   refreshAttributes();
     264                 :          0 :   emit changed();
     265                 :          0 : }
     266                 :            : 
     267                 :          0 : void QgsLayoutItemAttributeTable::setDisplayOnlyVisibleFeatures( const bool visibleOnly )
     268                 :            : {
     269                 :          0 :   if ( visibleOnly == mShowOnlyVisibleFeatures )
     270                 :            :   {
     271                 :          0 :     return;
     272                 :            :   }
     273                 :            : 
     274                 :          0 :   mShowOnlyVisibleFeatures = visibleOnly;
     275                 :          0 :   refreshAttributes();
     276                 :          0 :   emit changed();
     277                 :          0 : }
     278                 :            : 
     279                 :          0 : void QgsLayoutItemAttributeTable::setFilterToAtlasFeature( const bool filterToAtlas )
     280                 :            : {
     281                 :          0 :   if ( filterToAtlas == mFilterToAtlasIntersection )
     282                 :            :   {
     283                 :          0 :     return;
     284                 :            :   }
     285                 :            : 
     286                 :          0 :   mFilterToAtlasIntersection = filterToAtlas;
     287                 :          0 :   refreshAttributes();
     288                 :          0 :   emit changed();
     289                 :          0 : }
     290                 :            : 
     291                 :          0 : void QgsLayoutItemAttributeTable::setFilterFeatures( const bool filter )
     292                 :            : {
     293                 :          0 :   if ( filter == mFilterFeatures )
     294                 :            :   {
     295                 :          0 :     return;
     296                 :            :   }
     297                 :            : 
     298                 :          0 :   mFilterFeatures = filter;
     299                 :          0 :   refreshAttributes();
     300                 :          0 :   emit changed();
     301                 :          0 : }
     302                 :            : 
     303                 :          0 : void QgsLayoutItemAttributeTable::setFeatureFilter( const QString &expression )
     304                 :            : {
     305                 :          0 :   if ( expression == mFeatureFilter )
     306                 :            :   {
     307                 :          0 :     return;
     308                 :            :   }
     309                 :            : 
     310                 :          0 :   mFeatureFilter = expression;
     311                 :          0 :   refreshAttributes();
     312                 :          0 :   emit changed();
     313                 :          0 : }
     314                 :            : 
     315                 :          0 : void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields, bool refresh )
     316                 :            : {
     317                 :          0 :   QgsVectorLayer *source = sourceLayer();
     318                 :          0 :   if ( !source )
     319                 :          0 :   {
     320                 :          0 :     return;
     321                 :          0 :   }
     322                 :            : 
     323                 :            :   //rebuild columns list, taking only fields contained in supplied list
     324                 :          0 :   mColumns.clear();
     325                 :            : 
     326                 :          0 :   const QgsFields layerFields = source->fields();
     327                 :            : 
     328                 :          0 :   if ( !fields.isEmpty() )
     329                 :            :   {
     330                 :          0 :     for ( const QString &field : fields )
     331                 :            :     {
     332                 :          0 :       int attrIdx = layerFields.lookupField( field );
     333                 :          0 :       if ( attrIdx < 0 )
     334                 :            :       {
     335                 :          0 :         continue;
     336                 :            :       }
     337                 :          0 :       QString currentAlias = source->attributeDisplayName( attrIdx );
     338                 :          0 :       QgsLayoutTableColumn col;
     339                 :          0 :       col.setAttribute( layerFields.at( attrIdx ).name() );
     340                 :          0 :       col.setHeading( currentAlias );
     341                 :          0 :       mColumns.append( col );
     342                 :          0 :     }
     343                 :          0 :   }
     344                 :            :   else
     345                 :            :   {
     346                 :          0 :     //resetting, so add all attributes to columns
     347                 :          0 :     int idx = 0;
     348                 :          0 :     for ( const QgsField &field : layerFields )
     349                 :          0 :     {
     350                 :          0 :       QString currentAlias = source->attributeDisplayName( idx );
     351                 :          0 :       QgsLayoutTableColumn col;
     352                 :          0 :       col.setAttribute( field.name() );
     353                 :          0 :       col.setHeading( currentAlias );
     354                 :          0 :       mColumns.append( col );
     355                 :          0 :       idx++;
     356                 :          0 :     }
     357                 :            :   }
     358                 :            : 
     359                 :          0 :   if ( refresh )
     360                 :            :   {
     361                 :          0 :     refreshAttributes();
     362                 :          0 :   }
     363                 :          0 : }
     364                 :            : 
     365                 :          0 : void QgsLayoutItemAttributeTable::restoreFieldAliasMap( const QMap<int, QString> &map )
     366                 :            : {
     367                 :          0 :   QgsVectorLayer *source = sourceLayer();
     368                 :          0 :   if ( !source )
     369                 :            :   {
     370                 :          0 :     return;
     371                 :            :   }
     372                 :            : 
     373                 :          0 :   for ( int i = 0; i < mColumns.count(); i++ )
     374                 :            :   {
     375                 :          0 :     int attrIdx = source->fields().lookupField( mColumns[i].attribute() );
     376                 :          0 :     if ( map.contains( attrIdx ) )
     377                 :            :     {
     378                 :          0 :       mColumns[i].setHeading( map.value( attrIdx ) );
     379                 :          0 :     }
     380                 :            :     else
     381                 :            :     {
     382                 :          0 :       mColumns[i].setHeading( source->attributeDisplayName( attrIdx ) );
     383                 :            :     }
     384                 :          0 :   }
     385                 :          0 : }
     386                 :            : 
     387                 :          0 : bool QgsLayoutItemAttributeTable::getTableContents( QgsLayoutTableContents &contents )
     388                 :            : {
     389                 :          0 :   contents.clear();
     390                 :            : 
     391                 :          0 :   QgsVectorLayer *layer = sourceLayer();
     392                 :          0 :   if ( !layer )
     393                 :            :   {
     394                 :            :     //no source layer
     395                 :          0 :     return false;
     396                 :            :   }
     397                 :            : 
     398                 :          0 :   const QgsConditionalLayerStyles *conditionalStyles = layer->conditionalStyles();
     399                 :            : 
     400                 :          0 :   QgsExpressionContext context = createExpressionContext();
     401                 :          0 :   context.setFields( layer->fields() );
     402                 :            : 
     403                 :          0 :   QgsFeatureRequest req;
     404                 :          0 :   req.setExpressionContext( context );
     405                 :            : 
     406                 :            :   //prepare filter expression
     407                 :          0 :   std::unique_ptr<QgsExpression> filterExpression;
     408                 :          0 :   bool activeFilter = false;
     409                 :          0 :   if ( mFilterFeatures && !mFeatureFilter.isEmpty() )
     410                 :            :   {
     411                 :          0 :     filterExpression = std::make_unique< QgsExpression >( mFeatureFilter );
     412                 :          0 :     if ( !filterExpression->hasParserError() )
     413                 :            :     {
     414                 :          0 :       activeFilter = true;
     415                 :          0 :       req.setFilterExpression( mFeatureFilter );
     416                 :          0 :     }
     417                 :          0 :   }
     418                 :            : 
     419                 :            : #ifdef HAVE_SERVER_PYTHON_PLUGINS
     420                 :            :   if ( mLayout->renderContext().featureFilterProvider() )
     421                 :            :   {
     422                 :            :     mLayout->renderContext().featureFilterProvider()->filterFeatures( layer, req );
     423                 :            :   }
     424                 :            : #endif
     425                 :            : 
     426                 :          0 :   QgsRectangle selectionRect;
     427                 :          0 :   QgsGeometry visibleRegion;
     428                 :          0 :   std::unique_ptr< QgsGeometryEngine > visibleMapEngine;
     429                 :          0 :   if ( mMap && mShowOnlyVisibleFeatures )
     430                 :            :   {
     431                 :          0 :     visibleRegion = QgsGeometry::fromQPolygonF( mMap->visibleExtentPolygon() );
     432                 :          0 :     selectionRect = visibleRegion.boundingBox();
     433                 :            :     //transform back to layer CRS
     434                 :          0 :     QgsCoordinateTransform coordTransform( layer->crs(), mMap->crs(), mLayout->project() );
     435                 :            :     try
     436                 :            :     {
     437                 :          0 :       selectionRect = coordTransform.transformBoundingBox( selectionRect, QgsCoordinateTransform::ReverseTransform );
     438                 :          0 :       visibleRegion.transform( coordTransform, QgsCoordinateTransform::ReverseTransform );
     439                 :          0 :     }
     440                 :            :     catch ( QgsCsException &cse )
     441                 :            :     {
     442                 :          0 :       Q_UNUSED( cse )
     443                 :          0 :       return false;
     444                 :          0 :     }
     445                 :          0 :     visibleMapEngine.reset( QgsGeometry::createGeometryEngine( visibleRegion.constGet() ) );
     446                 :          0 :     visibleMapEngine->prepareGeometry();
     447                 :          0 :   }
     448                 :            : 
     449                 :          0 :   QgsGeometry atlasGeometry;
     450                 :          0 :   std::unique_ptr< QgsGeometryEngine > atlasGeometryEngine;
     451                 :          0 :   if ( mFilterToAtlasIntersection )
     452                 :            :   {
     453                 :          0 :     atlasGeometry = mLayout->reportContext().currentGeometry( layer->crs() );
     454                 :          0 :     if ( !atlasGeometry.isNull() )
     455                 :            :     {
     456                 :          0 :       if ( selectionRect.isNull() )
     457                 :            :       {
     458                 :          0 :         selectionRect = atlasGeometry.boundingBox();
     459                 :          0 :       }
     460                 :            :       else
     461                 :            :       {
     462                 :          0 :         selectionRect = selectionRect.intersect( atlasGeometry.boundingBox() );
     463                 :            :       }
     464                 :            : 
     465                 :          0 :       atlasGeometryEngine.reset( QgsGeometry::createGeometryEngine( atlasGeometry.constGet() ) );
     466                 :          0 :       atlasGeometryEngine->prepareGeometry();
     467                 :          0 :     }
     468                 :          0 :   }
     469                 :            : 
     470                 :          0 :   if ( mSource == QgsLayoutItemAttributeTable::RelationChildren )
     471                 :            :   {
     472                 :          0 :     QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
     473                 :          0 :     QgsFeature atlasFeature = mLayout->reportContext().feature();
     474                 :          0 :     req = relation.getRelatedFeaturesRequest( atlasFeature );
     475                 :          0 :   }
     476                 :            : 
     477                 :          0 :   if ( !selectionRect.isEmpty() )
     478                 :          0 :     req.setFilterRect( selectionRect );
     479                 :            : 
     480                 :          0 :   req.setFlags( mShowOnlyVisibleFeatures ? QgsFeatureRequest::ExactIntersect : QgsFeatureRequest::NoFlags );
     481                 :            : 
     482                 :          0 :   if ( mSource == QgsLayoutItemAttributeTable::AtlasFeature )
     483                 :            :   {
     484                 :            :     //source mode is current atlas feature
     485                 :          0 :     QgsFeature atlasFeature = mLayout->reportContext().feature();
     486                 :          0 :     req.setFilterFid( atlasFeature.id() );
     487                 :          0 :   }
     488                 :            : 
     489                 :          0 :   for ( const QgsLayoutTableColumn &column : std::as_const( mSortColumns ) )
     490                 :            :   {
     491                 :          0 :     req.addOrderBy( column.attribute(), column.sortOrder() == Qt::AscendingOrder );
     492                 :            :   }
     493                 :            : 
     494                 :          0 :   QgsFeature f;
     495                 :          0 :   int counter = 0;
     496                 :          0 :   QgsFeatureIterator fit = layer->getFeatures( req );
     497                 :            : 
     498                 :          0 :   mConditionalStyles.clear();
     499                 :          0 :   mFeatures.clear();
     500                 :            : 
     501                 :          0 :   QVector< QVector< Cell > > tempContents;
     502                 :          0 :   QgsLayoutTableContents existingContents;
     503                 :            : 
     504                 :          0 :   while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
     505                 :            :   {
     506                 :          0 :     context.setFeature( f );
     507                 :            :     //check feature against filter
     508                 :          0 :     if ( activeFilter && filterExpression )
     509                 :            :     {
     510                 :          0 :       QVariant result = filterExpression->evaluate( &context );
     511                 :            :       // skip this feature if the filter evaluation is false
     512                 :          0 :       if ( !result.toBool() )
     513                 :            :       {
     514                 :          0 :         continue;
     515                 :            :       }
     516                 :          0 :     }
     517                 :            : 
     518                 :            :     // check against exact map bounds
     519                 :          0 :     if ( visibleMapEngine )
     520                 :            :     {
     521                 :          0 :       if ( !f.hasGeometry() )
     522                 :          0 :         continue;
     523                 :            : 
     524                 :          0 :       if ( !visibleMapEngine->intersects( f.geometry().constGet() ) )
     525                 :          0 :         continue;
     526                 :          0 :     }
     527                 :            : 
     528                 :            :     //check against atlas feature intersection
     529                 :          0 :     if ( mFilterToAtlasIntersection )
     530                 :            :     {
     531                 :          0 :       if ( !f.hasGeometry() || !atlasGeometryEngine )
     532                 :            :       {
     533                 :          0 :         continue;
     534                 :            :       }
     535                 :            : 
     536                 :          0 :       if ( !atlasGeometryEngine->intersects( f.geometry().constGet() ) )
     537                 :          0 :         continue;
     538                 :          0 :     }
     539                 :            : 
     540                 :          0 :     QgsConditionalStyle rowStyle;
     541                 :            : 
     542                 :          0 :     if ( mUseConditionalStyling )
     543                 :            :     {
     544                 :          0 :       const QList<QgsConditionalStyle> styles = QgsConditionalStyle::matchingConditionalStyles( conditionalStyles->rowStyles(), QVariant(),  context );
     545                 :          0 :       rowStyle = QgsConditionalStyle::compressStyles( styles );
     546                 :          0 :     }
     547                 :            : 
     548                 :            :     // We need to build up two different lists here -- one is a pair of the cell contents along with the cell style.
     549                 :            :     // We need this one because we do a sorting step later, and we need to ensure that the cell styling is attached to the right row and sorted
     550                 :            :     // correctly when this occurs
     551                 :            :     // We also need a list of just the cell contents, so that we can do a quick check for row uniqueness (when the
     552                 :            :     // corresponding option is enabled)
     553                 :          0 :     QVector< Cell > currentRow;
     554                 :            : #ifdef HAVE_SERVER_PYTHON_PLUGINS
     555                 :            :     mColumns = filteredColumns();
     556                 :            : #endif
     557                 :          0 :     currentRow.reserve( mColumns.count() );
     558                 :          0 :     QgsLayoutTableRow rowContents;
     559                 :          0 :     rowContents.reserve( mColumns.count() );
     560                 :            : 
     561                 :          0 :     for ( const QgsLayoutTableColumn &column : std::as_const( mColumns ) )
     562                 :            :     {
     563                 :          0 :       int idx = layer->fields().lookupField( column.attribute() );
     564                 :            : 
     565                 :          0 :       QgsConditionalStyle style;
     566                 :            : 
     567                 :          0 :       if ( idx != -1 )
     568                 :            :       {
     569                 :          0 :         const QVariant val = f.attributes().at( idx );
     570                 :            : 
     571                 :          0 :         if ( mUseConditionalStyling )
     572                 :            :         {
     573                 :          0 :           QList<QgsConditionalStyle> styles = conditionalStyles->fieldStyles( layer->fields().at( idx ).name() );
     574                 :          0 :           styles = QgsConditionalStyle::matchingConditionalStyles( styles, val, context );
     575                 :          0 :           styles.insert( 0, rowStyle );
     576                 :          0 :           style = QgsConditionalStyle::compressStyles( styles );
     577                 :          0 :         }
     578                 :            : 
     579                 :          0 :         QVariant v = replaceWrapChar( val );
     580                 :          0 :         currentRow << Cell( v, style, f );
     581                 :          0 :         rowContents << v;
     582                 :          0 :       }
     583                 :            :       else
     584                 :            :       {
     585                 :            :         // Lets assume it's an expression
     586                 :          0 :         std::unique_ptr< QgsExpression > expression = std::make_unique< QgsExpression >( column.attribute() );
     587                 :          0 :         context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "row_number" ), counter + 1, true ) );
     588                 :          0 :         expression->prepare( &context );
     589                 :          0 :         QVariant value = expression->evaluate( &context );
     590                 :            : 
     591                 :          0 :         currentRow << Cell( value, rowStyle, f );
     592                 :          0 :         rowContents << value;
     593                 :          0 :       }
     594                 :          0 :     }
     595                 :            : 
     596                 :          0 :     if ( mShowUniqueRowsOnly )
     597                 :            :     {
     598                 :          0 :       if ( contentsContainsRow( existingContents, rowContents ) )
     599                 :          0 :         continue;
     600                 :          0 :     }
     601                 :            : 
     602                 :          0 :     tempContents << currentRow;
     603                 :          0 :     existingContents << rowContents;
     604                 :          0 :     ++counter;
     605                 :          0 :   }
     606                 :            : 
     607                 :            :   // build final table contents
     608                 :          0 :   contents.reserve( tempContents.size() );
     609                 :          0 :   mConditionalStyles.reserve( tempContents.size() );
     610                 :          0 :   mFeatures.reserve( tempContents.size() );
     611                 :          0 :   for ( auto it = tempContents.constBegin(); it != tempContents.constEnd(); ++it )
     612                 :            :   {
     613                 :          0 :     QgsLayoutTableRow row;
     614                 :          0 :     QList< QgsConditionalStyle > rowStyles;
     615                 :          0 :     row.reserve( it->size() );
     616                 :          0 :     rowStyles.reserve( it->size() );
     617                 :            : 
     618                 :          0 :     for ( auto cellIt = it->constBegin(); cellIt != it->constEnd(); ++cellIt )
     619                 :            :     {
     620                 :          0 :       row << cellIt->content;
     621                 :          0 :       rowStyles << cellIt->style;
     622                 :          0 :       if ( cellIt == it->constBegin() )
     623                 :          0 :         mFeatures << cellIt->feature;
     624                 :          0 :     }
     625                 :          0 :     contents << row;
     626                 :          0 :     mConditionalStyles << rowStyles;
     627                 :          0 :   }
     628                 :            : 
     629                 :          0 :   recalculateTableSize();
     630                 :          0 :   return true;
     631                 :          0 : }
     632                 :            : 
     633                 :          0 : QgsConditionalStyle QgsLayoutItemAttributeTable::conditionalCellStyle( int row, int column ) const
     634                 :            : {
     635                 :          0 :   if ( row >= mConditionalStyles.size() )
     636                 :          0 :     return QgsConditionalStyle();
     637                 :            : 
     638                 :          0 :   return mConditionalStyles.at( row ).at( column );
     639                 :          0 : }
     640                 :            : 
     641                 :          0 : QgsExpressionContextScope *QgsLayoutItemAttributeTable::scopeForCell( int row, int column ) const
     642                 :            : {
     643                 :          0 :   std::unique_ptr< QgsExpressionContextScope >scope( QgsLayoutTable::scopeForCell( row, column ) );
     644                 :          0 :   scope->setFeature( mFeatures.value( row ) );
     645                 :          0 :   scope->setFields( scope->feature().fields() );
     646                 :          0 :   return scope.release();
     647                 :          0 : }
     648                 :            : 
     649                 :          0 : QgsExpressionContext QgsLayoutItemAttributeTable::createExpressionContext() const
     650                 :            : {
     651                 :          0 :   QgsExpressionContext context = QgsLayoutTable::createExpressionContext();
     652                 :            : 
     653                 :          0 :   if ( mSource == LayerAttributes )
     654                 :            :   {
     655                 :          0 :     context.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer.get() ) );
     656                 :          0 :   }
     657                 :            : 
     658                 :          0 :   return context;
     659                 :          0 : }
     660                 :            : 
     661                 :          0 : void QgsLayoutItemAttributeTable::finalizeRestoreFromXml()
     662                 :            : {
     663                 :          0 :   QgsLayoutTable::finalizeRestoreFromXml();
     664                 :          0 :   if ( !mMap && !mMapUuid.isEmpty() && mLayout )
     665                 :            :   {
     666                 :          0 :     mMap = qobject_cast< QgsLayoutItemMap *>( mLayout->itemByUuid( mMapUuid, true ) );
     667                 :          0 :     if ( mMap )
     668                 :            :     {
     669                 :            :       //if we have found a valid map item, listen out to extent changes on it and refresh the table
     670                 :          0 :       connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutTable::refreshAttributes );
     671                 :          0 :       connect( mMap, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutTable::refreshAttributes );
     672                 :          0 :     }
     673                 :          0 :   }
     674                 :          0 : }
     675                 :            : 
     676                 :          0 : void QgsLayoutItemAttributeTable::refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property )
     677                 :            : {
     678                 :          0 :   QgsExpressionContext context = createExpressionContext();
     679                 :            : 
     680                 :          0 :   if ( mSource == QgsLayoutItemAttributeTable::LayerAttributes &&
     681                 :          0 :        ( property == QgsLayoutObject::AttributeTableSourceLayer || property == QgsLayoutObject::AllProperties ) )
     682                 :            :   {
     683                 :          0 :     mDataDefinedVectorLayer = nullptr;
     684                 :            : 
     685                 :          0 :     QString currentLayerIdentifier;
     686                 :          0 :     if ( QgsVectorLayer *currentLayer = mVectorLayer.get() )
     687                 :          0 :       currentLayerIdentifier = currentLayer->id();
     688                 :            : 
     689                 :          0 :     const QString layerIdentifier = mDataDefinedProperties.valueAsString( QgsLayoutObject::AttributeTableSourceLayer, context, currentLayerIdentifier );
     690                 :          0 :     QgsVectorLayer *ddLayer = qobject_cast< QgsVectorLayer * >( QgsLayoutUtils::mapLayerFromString( layerIdentifier, mLayout->project() ) );
     691                 :          0 :     if ( ddLayer )
     692                 :          0 :       mDataDefinedVectorLayer = ddLayer;
     693                 :          0 :   }
     694                 :            : 
     695                 :          0 :   QgsLayoutMultiFrame::refreshDataDefinedProperty( property );
     696                 :          0 : }
     697                 :            : 
     698                 :          0 : QVariant QgsLayoutItemAttributeTable::replaceWrapChar( const QVariant &variant ) const
     699                 :            : {
     700                 :            :   //avoid converting variants to string if not required (try to maintain original type for sorting)
     701                 :          0 :   if ( mWrapString.isEmpty() || !variant.toString().contains( mWrapString ) )
     702                 :          0 :     return variant;
     703                 :            : 
     704                 :          0 :   QString replaced = variant.toString();
     705                 :          0 :   replaced.replace( mWrapString, QLatin1String( "\n" ) );
     706                 :          0 :   return replaced;
     707                 :          0 : }
     708                 :            : 
     709                 :            : #ifdef HAVE_SERVER_PYTHON_PLUGINS
     710                 :            : QgsLayoutTableColumns QgsLayoutItemAttributeTable::filteredColumns()
     711                 :            : {
     712                 :            : 
     713                 :            :   QgsLayoutTableColumns allowedColumns { mColumns };
     714                 :            : 
     715                 :            :   // Filter columns
     716                 :            :   if ( mLayout->renderContext().featureFilterProvider() )
     717                 :            :   {
     718                 :            : 
     719                 :            :     QgsVectorLayer *source { sourceLayer() };
     720                 :            : 
     721                 :            :     if ( ! source )
     722                 :            :     {
     723                 :            :       return allowedColumns;
     724                 :            :     }
     725                 :            : 
     726                 :            :     QHash<const QString, QSet<QString>> columnAttributesMap;
     727                 :            :     QSet<QString> allowedAttributes;
     728                 :            : 
     729                 :            :     for ( const auto &c : std::as_const( allowedColumns ) )
     730                 :            :     {
     731                 :            :       if ( ! c.attribute().isEmpty() && ! columnAttributesMap.contains( c.attribute() ) )
     732                 :            :       {
     733                 :            :         columnAttributesMap[ c.attribute() ] = QSet<QString>();
     734                 :            :         const QgsExpression columnExp { c.attribute() };
     735                 :            :         const auto constRefs { columnExp.findNodes<QgsExpressionNodeColumnRef>() };
     736                 :            :         for ( const auto &cref : constRefs )
     737                 :            :         {
     738                 :            :           columnAttributesMap[ c.attribute() ].insert( cref->name() );
     739                 :            :           allowedAttributes.insert( cref->name() );
     740                 :            :         }
     741                 :            :       }
     742                 :            :     }
     743                 :            : 
     744                 :            :     const QStringList filteredAttributes { layout()->renderContext().featureFilterProvider()->layerAttributes( source, allowedAttributes.values() ) };
     745                 :            : #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
     746                 :            :     const QSet<QString> filteredAttributesSet( filteredAttributes.constBegin(), filteredAttributes.constEnd() );
     747                 :            : #else
     748                 :            :     const QSet<QString> filteredAttributesSet { filteredAttributes.toSet() };
     749                 :            : #endif
     750                 :            :     if ( filteredAttributesSet != allowedAttributes )
     751                 :            :     {
     752                 :            :       const auto forbidden { allowedAttributes.subtract( filteredAttributesSet ) };
     753                 :            :       allowedColumns.erase( std::remove_if( allowedColumns.begin(), allowedColumns.end(), [ &columnAttributesMap, &forbidden ]( QgsLayoutTableColumn & c ) -> bool
     754                 :            :       {
     755                 :            :         for ( const auto &f : std::as_const( forbidden ) )
     756                 :            :         {
     757                 :            :           if ( columnAttributesMap[ c.attribute() ].contains( f ) )
     758                 :            :           {
     759                 :            :             return true;
     760                 :            :           }
     761                 :            :         }
     762                 :            :         return false;
     763                 :            :       } ), allowedColumns.end() );
     764                 :            : 
     765                 :            :     }
     766                 :            :   }
     767                 :            : 
     768                 :            :   return allowedColumns;
     769                 :            : }
     770                 :            : #endif
     771                 :            : 
     772                 :          0 : QgsVectorLayer *QgsLayoutItemAttributeTable::sourceLayer() const
     773                 :            : {
     774                 :          0 :   switch ( mSource )
     775                 :            :   {
     776                 :            :     case QgsLayoutItemAttributeTable::AtlasFeature:
     777                 :          0 :       return mLayout->reportContext().layer();
     778                 :            :     case QgsLayoutItemAttributeTable::LayerAttributes:
     779                 :            :     {
     780                 :          0 :       if ( mDataDefinedVectorLayer )
     781                 :          0 :         return mDataDefinedVectorLayer;
     782                 :            :       else
     783                 :          0 :         return mVectorLayer.get();
     784                 :            :     }
     785                 :            :     case QgsLayoutItemAttributeTable::RelationChildren:
     786                 :            :     {
     787                 :          0 :       QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
     788                 :          0 :       return relation.referencingLayer();
     789                 :          0 :     }
     790                 :            :   }
     791                 :          0 :   return nullptr;
     792                 :          0 : }
     793                 :            : 
     794                 :          0 : void QgsLayoutItemAttributeTable::removeLayer( const QString &layerId )
     795                 :            : {
     796                 :          0 :   if ( mVectorLayer && mSource == QgsLayoutItemAttributeTable::LayerAttributes )
     797                 :            :   {
     798                 :          0 :     if ( layerId == mVectorLayer->id() )
     799                 :            :     {
     800                 :          0 :       mVectorLayer.setLayer( nullptr );
     801                 :            :       //remove existing columns
     802                 :          0 :       mColumns.clear();
     803                 :          0 :     }
     804                 :          0 :   }
     805                 :          0 : }
     806                 :            : 
     807                 :          0 : void QgsLayoutItemAttributeTable::setWrapString( const QString &wrapString )
     808                 :            : {
     809                 :          0 :   if ( wrapString == mWrapString )
     810                 :            :   {
     811                 :          0 :     return;
     812                 :            :   }
     813                 :            : 
     814                 :          0 :   mWrapString = wrapString;
     815                 :          0 :   refreshAttributes();
     816                 :          0 :   emit changed();
     817                 :          0 : }
     818                 :            : 
     819                 :          0 : bool QgsLayoutItemAttributeTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
     820                 :            : {
     821                 :          0 :   if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
     822                 :          0 :     return false;
     823                 :            : 
     824                 :          0 :   tableElem.setAttribute( QStringLiteral( "source" ), QString::number( static_cast< int >( mSource ) ) );
     825                 :          0 :   tableElem.setAttribute( QStringLiteral( "relationId" ), mRelationId );
     826                 :          0 :   tableElem.setAttribute( QStringLiteral( "showUniqueRowsOnly" ), mShowUniqueRowsOnly );
     827                 :          0 :   tableElem.setAttribute( QStringLiteral( "showOnlyVisibleFeatures" ), mShowOnlyVisibleFeatures );
     828                 :          0 :   tableElem.setAttribute( QStringLiteral( "filterToAtlasIntersection" ), mFilterToAtlasIntersection );
     829                 :          0 :   tableElem.setAttribute( QStringLiteral( "maxFeatures" ), mMaximumNumberOfFeatures );
     830                 :          0 :   tableElem.setAttribute( QStringLiteral( "filterFeatures" ), mFilterFeatures ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
     831                 :          0 :   tableElem.setAttribute( QStringLiteral( "featureFilter" ), mFeatureFilter );
     832                 :          0 :   tableElem.setAttribute( QStringLiteral( "wrapString" ), mWrapString );
     833                 :          0 :   tableElem.setAttribute( QStringLiteral( "useConditionalStyling" ), mUseConditionalStyling );
     834                 :            : 
     835                 :          0 :   if ( mMap )
     836                 :            :   {
     837                 :          0 :     tableElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
     838                 :          0 :   }
     839                 :            : 
     840                 :          0 :   if ( mVectorLayer )
     841                 :            :   {
     842                 :          0 :     tableElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer.layerId );
     843                 :          0 :     tableElem.setAttribute( QStringLiteral( "vectorLayerName" ), mVectorLayer.name );
     844                 :          0 :     tableElem.setAttribute( QStringLiteral( "vectorLayerSource" ), mVectorLayer.source );
     845                 :          0 :     tableElem.setAttribute( QStringLiteral( "vectorLayerProvider" ), mVectorLayer.provider );
     846                 :          0 :   }
     847                 :          0 :   return true;
     848                 :          0 : }
     849                 :            : 
     850                 :          0 : bool QgsLayoutItemAttributeTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
     851                 :            : {
     852                 :          0 :   if ( QgsVectorLayer *prevLayer = sourceLayer() )
     853                 :            :   {
     854                 :            :     //disconnect from previous layer
     855                 :          0 :     disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
     856                 :          0 :   }
     857                 :            : 
     858                 :          0 :   if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
     859                 :          0 :     return false;
     860                 :            : 
     861                 :          0 :   mSource = QgsLayoutItemAttributeTable::ContentSource( itemElem.attribute( QStringLiteral( "source" ), QStringLiteral( "0" ) ).toInt() );
     862                 :          0 :   mRelationId = itemElem.attribute( QStringLiteral( "relationId" ), QString() );
     863                 :            : 
     864                 :          0 :   if ( mSource == QgsLayoutItemAttributeTable::AtlasFeature )
     865                 :            :   {
     866                 :          0 :     mCurrentAtlasLayer = mLayout->reportContext().layer();
     867                 :          0 :   }
     868                 :            : 
     869                 :          0 :   mShowUniqueRowsOnly = itemElem.attribute( QStringLiteral( "showUniqueRowsOnly" ), QStringLiteral( "0" ) ).toInt();
     870                 :          0 :   mShowOnlyVisibleFeatures = itemElem.attribute( QStringLiteral( "showOnlyVisibleFeatures" ), QStringLiteral( "1" ) ).toInt();
     871                 :          0 :   mFilterToAtlasIntersection = itemElem.attribute( QStringLiteral( "filterToAtlasIntersection" ), QStringLiteral( "0" ) ).toInt();
     872                 :          0 :   mFilterFeatures = itemElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
     873                 :          0 :   mFeatureFilter = itemElem.attribute( QStringLiteral( "featureFilter" ), QString() );
     874                 :          0 :   mMaximumNumberOfFeatures = itemElem.attribute( QStringLiteral( "maxFeatures" ), QStringLiteral( "5" ) ).toInt();
     875                 :          0 :   mWrapString = itemElem.attribute( QStringLiteral( "wrapString" ) );
     876                 :          0 :   mUseConditionalStyling = itemElem.attribute( QStringLiteral( "useConditionalStyling" ), QStringLiteral( "0" ) ).toInt();
     877                 :            : 
     878                 :            :   //map
     879                 :          0 :   mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
     880                 :          0 :   if ( mMap )
     881                 :            :   {
     882                 :          0 :     disconnect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutTable::refreshAttributes );
     883                 :          0 :     disconnect( mMap, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutTable::refreshAttributes );
     884                 :          0 :     mMap = nullptr;
     885                 :          0 :   }
     886                 :            :   // setting new mMap occurs in finalizeRestoreFromXml
     887                 :            : 
     888                 :            :   //vector layer
     889                 :          0 :   QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
     890                 :          0 :   QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
     891                 :          0 :   QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
     892                 :          0 :   QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
     893                 :          0 :   mVectorLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
     894                 :          0 :   mVectorLayer.resolveWeakly( mLayout->project() );
     895                 :            : 
     896                 :            :   //connect to new layer
     897                 :          0 :   if ( QgsVectorLayer *newLayer = sourceLayer() )
     898                 :          0 :     connect( newLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
     899                 :            : 
     900                 :          0 :   refreshAttributes();
     901                 :            : 
     902                 :          0 :   emit changed();
     903                 :          0 :   return true;
     904                 :          0 : }
     905                 :            : 
     906                 :          0 : void QgsLayoutItemAttributeTable::setSource( const QgsLayoutItemAttributeTable::ContentSource source )
     907                 :            : {
     908                 :          0 :   if ( source == mSource )
     909                 :            :   {
     910                 :          0 :     return;
     911                 :            :   }
     912                 :            : 
     913                 :          0 :   QgsVectorLayer *prevLayer = sourceLayer();
     914                 :          0 :   mSource = source;
     915                 :          0 :   QgsVectorLayer *newLayer = sourceLayer();
     916                 :            : 
     917                 :          0 :   if ( newLayer != prevLayer )
     918                 :            :   {
     919                 :            :     //disconnect from previous layer
     920                 :          0 :     if ( prevLayer )
     921                 :            :     {
     922                 :          0 :       disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
     923                 :          0 :     }
     924                 :            : 
     925                 :            :     //connect to new layer
     926                 :          0 :     connect( newLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
     927                 :          0 :     if ( mSource == QgsLayoutItemAttributeTable::AtlasFeature )
     928                 :            :     {
     929                 :          0 :       mCurrentAtlasLayer = newLayer;
     930                 :          0 :     }
     931                 :            : 
     932                 :            :     //layer has changed as a result of the source change, so reset column list
     933                 :          0 :     resetColumns();
     934                 :          0 :   }
     935                 :            : 
     936                 :          0 :   refreshAttributes();
     937                 :          0 :   emit changed();
     938                 :          0 : }

Generated by: LCOV version 1.14