QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgslayoutitemattributetable.cpp
Go to the documentation of this file.
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 
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"
32 #include "qgsgeometryengine.h"
33 
34 //QgsLayoutAttributeTableCompare
35 
37 
41 class CORE_EXPORT QgsLayoutAttributeTableCompare
42 {
43  public:
44 
48  QgsLayoutAttributeTableCompare() = default;
49  bool operator()( const QgsLayoutTableRow &m1, const QgsLayoutTableRow &m2 )
50  {
51  return ( mAscending ? qgsVariantLessThan( m1[mCurrentSortColumn], m2[mCurrentSortColumn] )
52  : qgsVariantGreaterThan( m1[mCurrentSortColumn], m2[mCurrentSortColumn] ) );
53  }
54 
58  void setSortColumn( int column ) { mCurrentSortColumn = column; }
59 
64  void setAscending( bool ascending ) { mAscending = ascending; }
65 
66  private:
67  int mCurrentSortColumn = 0;
68  bool mAscending = true;
69 };
70 
72 
73 //
74 // QgsLayoutItemAttributeTable
75 //
76 
78  : QgsLayoutTable( layout )
79 {
80  if ( mLayout )
81  {
82  connect( mLayout->project(), static_cast < void ( QgsProject::* )( const QString & ) >( &QgsProject::layerWillBeRemoved ), this, &QgsLayoutItemAttributeTable::removeLayer );
83 
84  //coverage layer change = regenerate columns
85  connect( &mLayout->reportContext(), &QgsLayoutReportContext::layerChanged, this, &QgsLayoutItemAttributeTable::atlasLayerChanged );
86  }
88 }
89 
91 {
93 }
94 
96 {
97  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemTable.svg" ) );
98 }
99 
101 {
102  return new QgsLayoutItemAttributeTable( layout );
103 }
104 
106 {
107  return tr( "<Attribute table frame>" );
108 }
109 
111 {
112  if ( layer == mVectorLayer.get() )
113  {
114  //no change
115  return;
116  }
117 
118  QgsVectorLayer *prevLayer = sourceLayer();
119  mVectorLayer.setLayer( layer );
120 
121  if ( mSource == QgsLayoutItemAttributeTable::LayerAttributes && layer != prevLayer )
122  {
123  if ( prevLayer )
124  {
125  //disconnect from previous layer
126  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
127  }
128 
129  //rebuild column list to match all columns from layer
130  resetColumns();
131 
132  //listen for modifications to layer and refresh table when they occur
133  connect( mVectorLayer.get(), &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
134  }
135 
137  emit changed();
138 }
139 
141 {
142  if ( relationId == mRelationId )
143  {
144  //no change
145  return;
146  }
147 
148  QgsVectorLayer *prevLayer = sourceLayer();
149  mRelationId = relationId;
150  QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
151  QgsVectorLayer *newLayer = relation.referencingLayer();
152 
153  if ( mSource == QgsLayoutItemAttributeTable::RelationChildren && newLayer != prevLayer )
154  {
155  if ( prevLayer )
156  {
157  //disconnect from previous layer
158  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
159  }
160 
161  //rebuild column list to match all columns from layer
162  resetColumns();
163 
164  //listen for modifications to layer and refresh table when they occur
166  }
167 
169  emit changed();
170 }
171 
172 void QgsLayoutItemAttributeTable::atlasLayerChanged( QgsVectorLayer *layer )
173 {
174  if ( mSource != QgsLayoutItemAttributeTable::AtlasFeature || layer == mCurrentAtlasLayer )
175  {
176  //nothing to do
177  return;
178  }
179 
180  //atlas feature mode, atlas layer changed, so we need to reset columns
181  if ( mCurrentAtlasLayer )
182  {
183  //disconnect from previous layer
184  disconnect( mCurrentAtlasLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
185  }
186 
187  const bool mustRebuildColumns = static_cast< bool >( mCurrentAtlasLayer ) || mColumns.empty();
188  mCurrentAtlasLayer = layer;
189 
190  if ( mustRebuildColumns )
191  {
192  //rebuild column list to match all columns from layer
193  resetColumns();
194  }
195 
197 
198  //listen for modifications to layer and refresh table when they occur
200 }
201 
203 {
205  if ( !source )
206  {
207  return;
208  }
209 
210  //remove existing columns
211  qDeleteAll( mColumns );
212  mColumns.clear();
213 
214  //rebuild columns list from vector layer fields
215  int idx = 0;
216  const QgsFields sourceFields = source->fields();
217  for ( const auto &field : sourceFields )
218  {
219  QString currentAlias = source->attributeDisplayName( idx );
220  std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
221  col->setAttribute( field.name() );
222  col->setHeading( currentAlias );
223  mColumns.append( col.release() );
224  idx++;
225  }
226 }
227 
229 {
230  if ( map == mMap )
231  {
232  //no change
233  return;
234  }
235 
236  if ( mMap )
237  {
238  //disconnect from previous map
241  }
242  mMap = map;
243  if ( mMap )
244  {
245  //listen out for extent changes in linked map
248  }
250  emit changed();
251 }
252 
254 {
255  if ( features == mMaximumNumberOfFeatures )
256  {
257  return;
258  }
259 
260  mMaximumNumberOfFeatures = features;
262  emit changed();
263 }
264 
266 {
267  if ( uniqueOnly == mShowUniqueRowsOnly )
268  {
269  return;
270  }
271 
272  mShowUniqueRowsOnly = uniqueOnly;
274  emit changed();
275 }
276 
278 {
279  if ( visibleOnly == mShowOnlyVisibleFeatures )
280  {
281  return;
282  }
283 
284  mShowOnlyVisibleFeatures = visibleOnly;
286  emit changed();
287 }
288 
290 {
291  if ( filterToAtlas == mFilterToAtlasIntersection )
292  {
293  return;
294  }
295 
296  mFilterToAtlasIntersection = filterToAtlas;
298  emit changed();
299 }
300 
302 {
303  if ( filter == mFilterFeatures )
304  {
305  return;
306  }
307 
308  mFilterFeatures = filter;
310  emit changed();
311 }
312 
313 void QgsLayoutItemAttributeTable::setFeatureFilter( const QString &expression )
314 {
315  if ( expression == mFeatureFilter )
316  {
317  return;
318  }
319 
320  mFeatureFilter = expression;
322  emit changed();
323 }
324 
325 void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields, bool refresh )
326 {
328  if ( !source )
329  {
330  return;
331  }
332 
333  //rebuild columns list, taking only fields contained in supplied list
334  qDeleteAll( mColumns );
335  mColumns.clear();
336 
337  const QgsFields layerFields = source->fields();
338 
339  if ( !fields.isEmpty() )
340  {
341  for ( const QString &field : fields )
342  {
343  int attrIdx = layerFields.lookupField( field );
344  if ( attrIdx < 0 )
345  continue;
346 
347  QString currentAlias = source->attributeDisplayName( attrIdx );
348  std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
349  col->setAttribute( layerFields.at( attrIdx ).name() );
350  col->setHeading( currentAlias );
351  mColumns.append( col.release() );
352  }
353  }
354  else
355  {
356  //resetting, so add all attributes to columns
357  int idx = 0;
358  for ( const QgsField &field : layerFields )
359  {
360  QString currentAlias = source->attributeDisplayName( idx );
361  std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
362  col->setAttribute( field.name() );
363  col->setHeading( currentAlias );
364  mColumns.append( col.release() );
365  idx++;
366  }
367  }
368 
369  if ( refresh )
370  {
372  }
373 }
374 
375 void QgsLayoutItemAttributeTable::restoreFieldAliasMap( const QMap<int, QString> &map )
376 {
378  if ( !source )
379  {
380  return;
381  }
382 
383  for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
384  {
385  int attrIdx = source->fields().lookupField( column->attribute() );
386  if ( map.contains( attrIdx ) )
387  {
388  column->setHeading( map.value( attrIdx ) );
389  }
390  else
391  {
392  column->setHeading( source->attributeDisplayName( attrIdx ) );
393  }
394  }
395 }
396 
398 {
399  contents.clear();
400 
401  QgsVectorLayer *layer = sourceLayer();
402  if ( !layer )
403  {
404  //no source layer
405  return false;
406  }
407 
409  context.setFields( layer->fields() );
410 
411  QgsFeatureRequest req;
412 
413  //prepare filter expression
414  std::unique_ptr<QgsExpression> filterExpression;
415  bool activeFilter = false;
416  if ( mFilterFeatures && !mFeatureFilter.isEmpty() )
417  {
418  filterExpression = qgis::make_unique< QgsExpression >( mFeatureFilter );
419  if ( !filterExpression->hasParserError() )
420  {
421  activeFilter = true;
422  req.setFilterExpression( mFeatureFilter );
423  req.setExpressionContext( context );
424  }
425  }
426 
427  QgsRectangle selectionRect;
428  QgsGeometry visibleRegion;
429  std::unique_ptr< QgsGeometryEngine > visibleMapEngine;
430  if ( mMap && mShowOnlyVisibleFeatures )
431  {
432  visibleRegion = QgsGeometry::fromQPolygonF( mMap->visibleExtentPolygon() );
433  selectionRect = visibleRegion.boundingBox();
434  if ( layer )
435  {
436  //transform back to layer CRS
437  QgsCoordinateTransform coordTransform( layer->crs(), mMap->crs(), mLayout->project() );
438  try
439  {
440  selectionRect = coordTransform.transformBoundingBox( selectionRect, QgsCoordinateTransform::ReverseTransform );
441  visibleRegion.transform( coordTransform, QgsCoordinateTransform::ReverseTransform );
442  }
443  catch ( QgsCsException &cse )
444  {
445  Q_UNUSED( cse )
446  return false;
447  }
448  }
449  visibleMapEngine.reset( QgsGeometry::createGeometryEngine( visibleRegion.constGet() ) );
450  visibleMapEngine->prepareGeometry();
451  }
452 
453  QgsGeometry atlasGeometry;
454  std::unique_ptr< QgsGeometryEngine > atlasGeometryEngine;
455  if ( mFilterToAtlasIntersection )
456  {
457  atlasGeometry = mLayout->reportContext().currentGeometry( layer->crs() );
458  if ( !atlasGeometry.isNull() )
459  {
460  if ( selectionRect.isNull() )
461  {
462  selectionRect = atlasGeometry.boundingBox();
463  }
464  else
465  {
466  selectionRect = selectionRect.intersect( atlasGeometry.boundingBox() );
467  }
468 
469  atlasGeometryEngine.reset( QgsGeometry::createGeometryEngine( atlasGeometry.constGet() ) );
470  atlasGeometryEngine->prepareGeometry();
471  }
472  }
473 
475  {
476  QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
477  QgsFeature atlasFeature = mLayout->reportContext().feature();
478  req = relation.getRelatedFeaturesRequest( atlasFeature );
479  }
480 
481  if ( !selectionRect.isEmpty() )
482  req.setFilterRect( selectionRect );
483 
484  req.setFlags( mShowOnlyVisibleFeatures ? QgsFeatureRequest::ExactIntersect : QgsFeatureRequest::NoFlags );
485 
487  {
488  //source mode is current atlas feature
489  QgsFeature atlasFeature = mLayout->reportContext().feature();
490  req.setFilterFid( atlasFeature.id() );
491  }
492 
493  QgsFeature f;
494  int counter = 0;
495  QgsFeatureIterator fit = layer->getFeatures( req );
496 
497  while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
498  {
499  context.setFeature( f );
500  //check feature against filter
501  if ( activeFilter && filterExpression )
502  {
503  QVariant result = filterExpression->evaluate( &context );
504  // skip this feature if the filter evaluation is false
505  if ( !result.toBool() )
506  {
507  continue;
508  }
509  }
510 
511  // check against exact map bounds
512  if ( visibleMapEngine )
513  {
514  if ( !f.hasGeometry() )
515  continue;
516 
517  if ( !visibleMapEngine->intersects( f.geometry().constGet() ) )
518  continue;
519  }
520 
521  //check against atlas feature intersection
522  if ( mFilterToAtlasIntersection )
523  {
524  if ( !f.hasGeometry() || !atlasGeometryEngine )
525  {
526  continue;
527  }
528 
529  if ( !atlasGeometryEngine->intersects( f.geometry().constGet() ) )
530  continue;
531  }
532 
533  QgsLayoutTableRow currentRow;
534  currentRow.reserve( mColumns.count() );
535 
536  for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
537  {
538  int idx = layer->fields().lookupField( column->attribute() );
539  if ( idx != -1 )
540  {
541  currentRow << replaceWrapChar( f.attributes().at( idx ) );
542  }
543  else
544  {
545  // Lets assume it's an expression
546  std::unique_ptr< QgsExpression > expression = qgis::make_unique< QgsExpression >( column->attribute() );
547  context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "row_number" ), counter + 1, true ) );
548  expression->prepare( &context );
549  QVariant value = expression->evaluate( &context );
550  currentRow << value;
551  }
552  }
553 
554  if ( !mShowUniqueRowsOnly || !contentsContainsRow( contents, currentRow ) )
555  {
556  contents << currentRow;
557  ++counter;
558  }
559  }
560 
561  //sort the list, starting with the last attribute
562  QgsLayoutAttributeTableCompare c;
563  QVector< QPair<int, bool> > sortColumns = sortAttributes();
564  for ( int i = sortColumns.size() - 1; i >= 0; --i )
565  {
566  c.setSortColumn( sortColumns.at( i ).first );
567  c.setAscending( sortColumns.at( i ).second );
568  std::stable_sort( contents.begin(), contents.end(), c );
569  }
570 
572  return true;
573 }
574 
576 {
578 
579  if ( mSource == LayerAttributes )
580  {
581  context.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer.get() ) );
582  }
583 
584  return context;
585 }
586 
588 {
590  if ( !mMap && !mMapUuid.isEmpty() && mLayout )
591  {
592  mMap = qobject_cast< QgsLayoutItemMap *>( mLayout->itemByUuid( mMapUuid, true ) );
593  if ( mMap )
594  {
595  //if we have found a valid map item, listen out to extent changes on it and refresh the table
598  }
599  }
600 }
601 
603 {
605 
608  {
609  mDataDefinedVectorLayer = nullptr;
610 
611  QString currentLayerIdentifier;
612  if ( QgsVectorLayer *currentLayer = mVectorLayer.get() )
613  currentLayerIdentifier = currentLayer->id();
614 
615  const QString layerIdentifier = mDataDefinedProperties.valueAsString( QgsLayoutObject::AttributeTableSourceLayer, context, currentLayerIdentifier );
616  QgsVectorLayer *ddLayer = qobject_cast< QgsVectorLayer * >( QgsLayoutUtils::mapLayerFromString( layerIdentifier, mLayout->project() ) );
617  if ( ddLayer )
618  mDataDefinedVectorLayer = ddLayer;
619  }
620 
622 }
623 
624 QVariant QgsLayoutItemAttributeTable::replaceWrapChar( const QVariant &variant ) const
625 {
626  //avoid converting variants to string if not required (try to maintain original type for sorting)
627  if ( mWrapString.isEmpty() || !variant.toString().contains( mWrapString ) )
628  return variant;
629 
630  QString replaced = variant.toString();
631  replaced.replace( mWrapString, QLatin1String( "\n" ) );
632  return replaced;
633 }
634 
636 {
637  switch ( mSource )
638  {
640  return mLayout->reportContext().layer();
642  {
643  if ( mDataDefinedVectorLayer )
644  return mDataDefinedVectorLayer;
645  else
646  return mVectorLayer.get();
647  }
649  {
650  QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
651  return relation.referencingLayer();
652  }
653  }
654  return nullptr;
655 }
656 
657 void QgsLayoutItemAttributeTable::removeLayer( const QString &layerId )
658 {
659  if ( mVectorLayer && mSource == QgsLayoutItemAttributeTable::LayerAttributes )
660  {
661  if ( layerId == mVectorLayer->id() )
662  {
663  mVectorLayer.setLayer( nullptr );
664  //remove existing columns
665  qDeleteAll( mColumns );
666  mColumns.clear();
667  }
668  }
669 }
670 
671 static bool columnsBySortRank( QPair<int, QgsLayoutTableColumn * > a, QPair<int, QgsLayoutTableColumn * > b )
672 {
673  return a.second->sortByRank() < b.second->sortByRank();
674 }
675 
676 QVector<QPair<int, bool> > QgsLayoutItemAttributeTable::sortAttributes() const
677 {
678  //generate list of all sorted columns
679  QVector< QPair<int, QgsLayoutTableColumn * > > sortedColumns;
680  int idx = 0;
681  for ( QgsLayoutTableColumn *column : mColumns )
682  {
683  if ( column->sortByRank() > 0 )
684  {
685  sortedColumns.append( qMakePair( idx, column ) );
686  }
687  idx++;
688  }
689 
690  //sort columns by rank
691  std::sort( sortedColumns.begin(), sortedColumns.end(), columnsBySortRank );
692 
693  //generate list of column index, bool for sort direction (to match 2.0 api)
694  QVector<QPair<int, bool> > attributesBySortRank;
695  attributesBySortRank.reserve( sortedColumns.size() );
696  for ( auto &column : qgis::as_const( sortedColumns ) )
697  {
698  attributesBySortRank.append( qMakePair( column.first,
699  column.second->sortOrder() == Qt::AscendingOrder ) );
700  }
701  return attributesBySortRank;
702 }
703 
705 {
706  if ( wrapString == mWrapString )
707  {
708  return;
709  }
710 
711  mWrapString = wrapString;
713  emit changed();
714 }
715 
716 bool QgsLayoutItemAttributeTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
717 {
718  if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
719  return false;
720 
721  tableElem.setAttribute( QStringLiteral( "source" ), QString::number( static_cast< int >( mSource ) ) );
722  tableElem.setAttribute( QStringLiteral( "relationId" ), mRelationId );
723  tableElem.setAttribute( QStringLiteral( "showUniqueRowsOnly" ), mShowUniqueRowsOnly );
724  tableElem.setAttribute( QStringLiteral( "showOnlyVisibleFeatures" ), mShowOnlyVisibleFeatures );
725  tableElem.setAttribute( QStringLiteral( "filterToAtlasIntersection" ), mFilterToAtlasIntersection );
726  tableElem.setAttribute( QStringLiteral( "maxFeatures" ), mMaximumNumberOfFeatures );
727  tableElem.setAttribute( QStringLiteral( "filterFeatures" ), mFilterFeatures ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
728  tableElem.setAttribute( QStringLiteral( "featureFilter" ), mFeatureFilter );
729  tableElem.setAttribute( QStringLiteral( "wrapString" ), mWrapString );
730 
731  if ( mMap )
732  {
733  tableElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
734  }
735 
736  if ( mVectorLayer )
737  {
738  tableElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer.layerId );
739  tableElem.setAttribute( QStringLiteral( "vectorLayerName" ), mVectorLayer.name );
740  tableElem.setAttribute( QStringLiteral( "vectorLayerSource" ), mVectorLayer.source );
741  tableElem.setAttribute( QStringLiteral( "vectorLayerProvider" ), mVectorLayer.provider );
742  }
743  return true;
744 }
745 
746 bool QgsLayoutItemAttributeTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
747 {
748  QgsVectorLayer *prevLayer = sourceLayer();
749  if ( prevLayer )
750  {
751  //disconnect from previous layer
752  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
753  }
754 
755  if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
756  return false;
757 
758  mSource = QgsLayoutItemAttributeTable::ContentSource( itemElem.attribute( QStringLiteral( "source" ), QStringLiteral( "0" ) ).toInt() );
759  mRelationId = itemElem.attribute( QStringLiteral( "relationId" ), QString() );
760 
762  {
763  mCurrentAtlasLayer = mLayout->reportContext().layer();
764  }
765 
766  mShowUniqueRowsOnly = itemElem.attribute( QStringLiteral( "showUniqueRowsOnly" ), QStringLiteral( "0" ) ).toInt();
767  mShowOnlyVisibleFeatures = itemElem.attribute( QStringLiteral( "showOnlyVisibleFeatures" ), QStringLiteral( "1" ) ).toInt();
768  mFilterToAtlasIntersection = itemElem.attribute( QStringLiteral( "filterToAtlasIntersection" ), QStringLiteral( "0" ) ).toInt();
769  mFilterFeatures = itemElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
770  mFeatureFilter = itemElem.attribute( QStringLiteral( "featureFilter" ), QString() );
771  mMaximumNumberOfFeatures = itemElem.attribute( QStringLiteral( "maxFeatures" ), QStringLiteral( "5" ) ).toInt();
772  mWrapString = itemElem.attribute( QStringLiteral( "wrapString" ) );
773 
774  //map
775  mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
776  if ( mMap )
777  {
780  mMap = nullptr;
781  }
782  // setting new mMap occurs in finalizeRestoreFromXml
783 
784  //vector layer
785  QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
786  QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
787  QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
788  QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
789  mVectorLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
790  mVectorLayer.resolveWeakly( mLayout->project() );
791 
792  //connect to new layer
794 
796 
797  emit changed();
798  return true;
799 }
800 
802 {
803  if ( source == mSource )
804  {
805  return;
806  }
807 
808  QgsVectorLayer *prevLayer = sourceLayer();
809  mSource = source;
810  QgsVectorLayer *newLayer = sourceLayer();
811 
812  if ( newLayer != prevLayer )
813  {
814  //disconnect from previous layer
815  if ( prevLayer )
816  {
817  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
818  }
819 
820  //connect to new layer
823  {
824  mCurrentAtlasLayer = newLayer;
825  }
826 
827  //layer has changed as a result of the source change, so reset column list
828  resetColumns();
829  }
830 
832  emit changed();
833 }
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
QString displayName() const override
Returns the multiframe display name.
QgsFeatureId id
Definition: qgsfeature.h:64
The class is used as a container of context for various read/write operations on other objects...
Wrapper for iterator of features from vector data provider or vector layer.
Single variable definition for use within a QgsExpressionContextScope.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QString relationId() const
Returns the relation id which the table displays child features from.
QgsExpressionContext createExpressionContext() const override
Creates an expression context relating to the objects&#39; current state.
void setMaximumNumberOfFeatures(int features)
Sets the maximum number of features shown by the table.
QString name
Definition: qgsfield.h:58
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Use exact geometry intersection (slower) instead of bounding boxes.
int type() const override
Returns unique multiframe type id.
A class to display a table in the print layout, and allow the table to span over multiple frames...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void extentChanged()
Emitted when the map&#39;s extent changes.
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:46
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
TYPE * resolveWeakly(const QgsProject *project)
Resolves the map layer by attempting to find a matching layer in a project using a weak match...
virtual void refreshAttributes()
Refreshes the contents shown in the table by querying for new data.
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
Table shows attributes from related child features.
QString wrapString() const
Returns the string used to wrap the contents of the table cells by.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
Definition: qgis.cpp:221
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Table shows attributes from features in a vector layer.
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition: qgis.cpp:153
Stores properties of a column for a QgsLayoutTable.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
void setFilterToAtlasFeature(bool filterToAtlas)
Sets attribute table to only show features which intersect the current atlas feature.
void resetColumns()
Resets the attribute table&#39;s columns to match the vector layer&#39;s fields.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Attribute table source layer.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Layout graphical items for displaying a map.
QString provider
Weak reference to layer provider.
QString layerId
Original layer ID.
QgsPropertyCollection mDataDefinedProperties
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
const QgsLayout * layout() const
Returns the layout the object is attached to.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:426
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Definition: qgsrectangle.h:312
QString name
Weak reference to layer name.
void setFeatureFilter(const QString &expression)
Sets the expression used for filtering features in the table.
QPointer< QgsLayout > mLayout
QgsVectorLayer * sourceLayer() const
Returns the source layer for the table, considering the table source mode.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void setFilterFeatures(bool filter)
Sets whether the feature filter is active for the attribute table.
void setDisplayOnlyVisibleFeatures(bool visibleOnly)
Sets the attribute table to only show features which are visible in a map item.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
Reads and writes project states.
Definition: qgsproject.h:89
A layout table subclass that displays attributes from a vector layer.
Table shows attributes from the current atlas feature.
void layerChanged(QgsVectorLayer *layer)
Emitted when the context&#39;s layer is changed.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
virtual void finalizeRestoreFromXml()
Called after all pending items have been restored from XML.
void setLayer(TYPE *l)
Sets the reference to point to a specified layer.
QString source
Weak reference to layer public source.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProject *project)
Resolves a string into a map layer from a given project.
static QgsLayoutItemAttributeTable * create(QgsLayout *layout)
Returns a new QgsLayoutItemAttributeTable for the specified parent layout.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QVector< QPair< int, bool > > sortAttributes() const
Returns the attributes used to sort the table&#39;s features.
void setVectorLayer(QgsVectorLayer *layer)
Sets the vector layer from which to display feature attributes.
QPolygonF visibleExtentPolygon() const
Returns a polygon representing the current visible map extent, considering map extents and rotation...
void mapRotationChanged(double newRotation)
Emitted when the map&#39;s rotation changes.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void setSource(ContentSource source)
Sets the source for attributes to show in table body.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
void setDisplayedFields(const QStringList &fields, bool refresh=true)
Sets the attributes to display in the table.
void layerWillBeRemoved(const QString &layerId)
Emitted when a layer is about to be removed from the registry.
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string...
QgsLayoutTableColumns mColumns
Columns to show in table.
void setUniqueRowsOnly(bool uniqueOnly)
Sets attribute table to only show unique rows.
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
Transform from destination to source CRS.
QgsLayoutTableContents & contents()
Returns the current contents of the table.
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
QgsLayoutItemAttributeTable(QgsLayout *layout)
Constructor for QgsLayoutItemAttributeTable, attached to the specified layout.
void setWrapString(const QString &wrapString)
Sets a string to wrap the contents of the table cells by.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
virtual QString uuid() const
Returns the item identification string.
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:436
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Class for doing transforms between two map coordinate systems.
void setRelationId(const QString &id)
Sets the relation id from which to display child features.
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties) override
Refreshes a data defined property for the multi frame by reevaluating the property&#39;s value and redraw...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsGeometry geometry
Definition: qgsfeature.h:67
void setMap(QgsLayoutItemMap *map)
Sets a layout map to use to limit the extent of features shown in the attribute table.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
ContentSource
Specifies the content source for the attribute table.
ContentSource source() const
Returns the source for attributes shown in the table body.
QgsLayoutItemMap * map() const
Returns the layout map whose extents are controlling the features shown in the table.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
void changed()
Emitted when the object&#39;s properties change.
Represents a vector layer which manages a vector based data sets.
TYPE * get() const
Returns a pointer to the layer, or nullptr if the reference has not yet been matched to a layer...
DataDefinedProperty
Data defined properties for different item types.
bool getTableContents(QgsLayoutTableContents &contents) override
Queries the attribute table&#39;s vector layer for attributes to show in the table.
QIcon icon() const override
Returns the item&#39;s icon.
void layerModified()
Emitted when modifications has been done on layer.
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else...
bool contentsContainsRow(const QgsLayoutTableContents &contents, const QgsLayoutTableRow &row) const
Checks whether a table contents contains a given row.
QgsAttributes attributes
Definition: qgsfeature.h:65
QVector< QgsLayoutTableRow > QgsLayoutTableContents
List of QgsLayoutTableRows, representing rows and column cell contents for a QgsLayoutTable.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:85
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
All properties for item.
QVector< QVariant > QgsLayoutTableRow
List of QVariants, representing a the contents of a single row in a QgsComposerTable.
void recalculateTableSize()
Recalculates and updates the size of the table and all table frames.
void refresh() override
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties)
Refreshes a data defined property for the multi frame by reevaluating the property&#39;s value and redraw...