QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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"
31 #include "qgsgeometryengine.h"
32 
33 //QgsLayoutAttributeTableCompare
34 
36 
40 class CORE_EXPORT QgsLayoutAttributeTableCompare
41 {
42  public:
43 
47  QgsLayoutAttributeTableCompare() = default;
48  bool operator()( const QgsLayoutTableRow &m1, const QgsLayoutTableRow &m2 )
49  {
50  return ( mAscending ? qgsVariantLessThan( m1[mCurrentSortColumn], m2[mCurrentSortColumn] )
51  : qgsVariantGreaterThan( m1[mCurrentSortColumn], m2[mCurrentSortColumn] ) );
52  }
53 
57  void setSortColumn( int column ) { mCurrentSortColumn = column; }
58 
63  void setAscending( bool ascending ) { mAscending = ascending; }
64 
65  private:
66  int mCurrentSortColumn = 0;
67  bool mAscending = true;
68 };
69 
71 
72 //
73 // QgsLayoutItemAttributeTable
74 //
75 
77  : QgsLayoutTable( layout )
78 {
79  if ( mLayout )
80  {
81  connect( mLayout->project(), static_cast < void ( QgsProject::* )( const QString & ) >( &QgsProject::layerWillBeRemoved ), this, &QgsLayoutItemAttributeTable::removeLayer );
82 
83  //coverage layer change = regenerate columns
84  connect( &mLayout->reportContext(), &QgsLayoutReportContext::layerChanged, this, &QgsLayoutItemAttributeTable::atlasLayerChanged );
85  }
87 }
88 
90 {
92 }
93 
95 {
96  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemTable.svg" ) );
97 }
98 
100 {
101  return new QgsLayoutItemAttributeTable( layout );
102 }
103 
105 {
106  return tr( "<Attribute table frame>" );
107 }
108 
110 {
111  if ( layer == mVectorLayer.get() )
112  {
113  //no change
114  return;
115  }
116 
117  QgsVectorLayer *prevLayer = sourceLayer();
118  mVectorLayer.setLayer( layer );
119 
120  if ( mSource == QgsLayoutItemAttributeTable::LayerAttributes && layer != prevLayer )
121  {
122  if ( prevLayer )
123  {
124  //disconnect from previous layer
125  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
126  }
127 
128  //rebuild column list to match all columns from layer
129  resetColumns();
130 
131  //listen for modifications to layer and refresh table when they occur
132  connect( mVectorLayer.get(), &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
133  }
134 
136  emit changed();
137 }
138 
140 {
141  if ( relationId == mRelationId )
142  {
143  //no change
144  return;
145  }
146 
147  QgsVectorLayer *prevLayer = sourceLayer();
148  mRelationId = relationId;
149  QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
150  QgsVectorLayer *newLayer = relation.referencingLayer();
151 
152  if ( mSource == QgsLayoutItemAttributeTable::RelationChildren && newLayer != prevLayer )
153  {
154  if ( prevLayer )
155  {
156  //disconnect from previous layer
157  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
158  }
159 
160  //rebuild column list to match all columns from layer
161  resetColumns();
162 
163  //listen for modifications to layer and refresh table when they occur
165  }
166 
168  emit changed();
169 }
170 
171 void QgsLayoutItemAttributeTable::atlasLayerChanged( QgsVectorLayer *layer )
172 {
173  if ( mSource != QgsLayoutItemAttributeTable::AtlasFeature || layer == mCurrentAtlasLayer )
174  {
175  //nothing to do
176  return;
177  }
178 
179  //atlas feature mode, atlas layer changed, so we need to reset columns
180  if ( mCurrentAtlasLayer )
181  {
182  //disconnect from previous layer
183  disconnect( mCurrentAtlasLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
184  }
185 
186  const bool mustRebuildColumns = static_cast< bool >( mCurrentAtlasLayer ) || mColumns.empty();
187  mCurrentAtlasLayer = layer;
188 
189  if ( mustRebuildColumns )
190  {
191  //rebuild column list to match all columns from layer
192  resetColumns();
193  }
194 
196 
197  //listen for modifications to layer and refresh table when they occur
199 }
200 
202 {
204  if ( !source )
205  {
206  return;
207  }
208 
209  //remove existing columns
210  qDeleteAll( mColumns );
211  mColumns.clear();
212 
213  //rebuild columns list from vector layer fields
214  int idx = 0;
215  const QgsFields sourceFields = source->fields();
216  for ( const auto &field : sourceFields )
217  {
218  QString currentAlias = source->attributeDisplayName( idx );
219  std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
220  col->setAttribute( field.name() );
221  col->setHeading( currentAlias );
222  mColumns.append( col.release() );
223  idx++;
224  }
225 }
226 
227 void QgsLayoutItemAttributeTable::disconnectCurrentMap()
228 {
229  if ( !mMap )
230  {
231  return;
232  }
233 
236  disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemAttributeTable::disconnectCurrentMap );
237  mMap = nullptr;
238 }
239 
241 {
242  if ( map == mMap )
243  {
244  //no change
245  return;
246  }
247  disconnectCurrentMap();
248 
249  mMap = map;
250  if ( mMap )
251  {
252  //listen out for extent changes in linked map
255  connect( mMap, &QObject::destroyed, this, &QgsLayoutItemAttributeTable::disconnectCurrentMap );
256  }
258  emit changed();
259 }
260 
262 {
263  if ( features == mMaximumNumberOfFeatures )
264  {
265  return;
266  }
267 
268  mMaximumNumberOfFeatures = features;
270  emit changed();
271 }
272 
274 {
275  if ( uniqueOnly == mShowUniqueRowsOnly )
276  {
277  return;
278  }
279 
280  mShowUniqueRowsOnly = uniqueOnly;
282  emit changed();
283 }
284 
286 {
287  if ( visibleOnly == mShowOnlyVisibleFeatures )
288  {
289  return;
290  }
291 
292  mShowOnlyVisibleFeatures = visibleOnly;
294  emit changed();
295 }
296 
298 {
299  if ( filterToAtlas == mFilterToAtlasIntersection )
300  {
301  return;
302  }
303 
304  mFilterToAtlasIntersection = filterToAtlas;
306  emit changed();
307 }
308 
310 {
311  if ( filter == mFilterFeatures )
312  {
313  return;
314  }
315 
316  mFilterFeatures = filter;
318  emit changed();
319 }
320 
321 void QgsLayoutItemAttributeTable::setFeatureFilter( const QString &expression )
322 {
323  if ( expression == mFeatureFilter )
324  {
325  return;
326  }
327 
328  mFeatureFilter = expression;
330  emit changed();
331 }
332 
333 void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields, bool refresh )
334 {
336  if ( !source )
337  {
338  return;
339  }
340 
341  //rebuild columns list, taking only fields contained in supplied list
342  qDeleteAll( mColumns );
343  mColumns.clear();
344 
345  const QgsFields layerFields = source->fields();
346 
347  if ( !fields.isEmpty() )
348  {
349  for ( const QString &field : fields )
350  {
351  int attrIdx = layerFields.lookupField( field );
352  if ( attrIdx < 0 )
353  continue;
354 
355  QString currentAlias = source->attributeDisplayName( attrIdx );
356  std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
357  col->setAttribute( layerFields.at( attrIdx ).name() );
358  col->setHeading( currentAlias );
359  mColumns.append( col.release() );
360  }
361  }
362  else
363  {
364  //resetting, so add all attributes to columns
365  int idx = 0;
366  for ( const QgsField &field : layerFields )
367  {
368  QString currentAlias = source->attributeDisplayName( idx );
369  std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
370  col->setAttribute( field.name() );
371  col->setHeading( currentAlias );
372  mColumns.append( col.release() );
373  idx++;
374  }
375  }
376 
377  if ( refresh )
378  {
380  }
381 }
382 
383 void QgsLayoutItemAttributeTable::restoreFieldAliasMap( const QMap<int, QString> &map )
384 {
386  if ( !source )
387  {
388  return;
389  }
390 
391  for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
392  {
393  int attrIdx = source->fields().lookupField( column->attribute() );
394  if ( map.contains( attrIdx ) )
395  {
396  column->setHeading( map.value( attrIdx ) );
397  }
398  else
399  {
400  column->setHeading( source->attributeDisplayName( attrIdx ) );
401  }
402  }
403 }
404 
406 {
407  contents.clear();
408 
409  QgsVectorLayer *layer = sourceLayer();
410  if ( !layer )
411  {
412  //no source layer
413  return false;
414  }
415 
417  context.setFields( layer->fields() );
418 
419  QgsFeatureRequest req;
420 
421  //prepare filter expression
422  std::unique_ptr<QgsExpression> filterExpression;
423  bool activeFilter = false;
424  if ( mFilterFeatures && !mFeatureFilter.isEmpty() )
425  {
426  filterExpression = qgis::make_unique< QgsExpression >( mFeatureFilter );
427  if ( !filterExpression->hasParserError() )
428  {
429  activeFilter = true;
430  req.setFilterExpression( mFeatureFilter );
431  req.setExpressionContext( context );
432  }
433  }
434 
435  QgsRectangle selectionRect;
436  QgsGeometry visibleRegion;
437  std::unique_ptr< QgsGeometryEngine > visibleMapEngine;
438  if ( mMap && mShowOnlyVisibleFeatures )
439  {
440  visibleRegion = QgsGeometry::fromQPolygonF( mMap->visibleExtentPolygon() );
441  selectionRect = visibleRegion.boundingBox();
442  if ( layer )
443  {
444  //transform back to layer CRS
445  QgsCoordinateTransform coordTransform( layer->crs(), mMap->crs(), mLayout->project() );
446  try
447  {
448  selectionRect = coordTransform.transformBoundingBox( selectionRect, QgsCoordinateTransform::ReverseTransform );
449  visibleRegion.transform( coordTransform, QgsCoordinateTransform::ReverseTransform );
450  }
451  catch ( QgsCsException &cse )
452  {
453  Q_UNUSED( cse )
454  return false;
455  }
456  }
457  visibleMapEngine.reset( QgsGeometry::createGeometryEngine( visibleRegion.constGet() ) );
458  visibleMapEngine->prepareGeometry();
459  }
460 
461  QgsGeometry atlasGeometry;
462  std::unique_ptr< QgsGeometryEngine > atlasGeometryEngine;
463  if ( mFilterToAtlasIntersection )
464  {
465  atlasGeometry = mLayout->reportContext().currentGeometry( layer->crs() );
466  if ( !atlasGeometry.isNull() )
467  {
468  if ( selectionRect.isNull() )
469  {
470  selectionRect = atlasGeometry.boundingBox();
471  }
472  else
473  {
474  selectionRect = selectionRect.intersect( atlasGeometry.boundingBox() );
475  }
476 
477  atlasGeometryEngine.reset( QgsGeometry::createGeometryEngine( atlasGeometry.constGet() ) );
478  atlasGeometryEngine->prepareGeometry();
479  }
480  }
481 
483  {
484  QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
485  QgsFeature atlasFeature = mLayout->reportContext().feature();
486  req = relation.getRelatedFeaturesRequest( atlasFeature );
487  }
488 
489  if ( !selectionRect.isEmpty() )
490  req.setFilterRect( selectionRect );
491 
492  req.setFlags( mShowOnlyVisibleFeatures ? QgsFeatureRequest::ExactIntersect : QgsFeatureRequest::NoFlags );
493 
495  {
496  //source mode is current atlas feature
497  QgsFeature atlasFeature = mLayout->reportContext().feature();
498  req.setFilterFid( atlasFeature.id() );
499  }
500 
501  QgsFeature f;
502  int counter = 0;
503  QgsFeatureIterator fit = layer->getFeatures( req );
504 
505  while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
506  {
507  context.setFeature( f );
508  //check feature against filter
509  if ( activeFilter && filterExpression )
510  {
511  QVariant result = filterExpression->evaluate( &context );
512  // skip this feature if the filter evaluation is false
513  if ( !result.toBool() )
514  {
515  continue;
516  }
517  }
518 
519  // check against exact map bounds
520  if ( visibleMapEngine )
521  {
522  if ( !f.hasGeometry() )
523  continue;
524 
525  if ( !visibleMapEngine->intersects( f.geometry().constGet() ) )
526  continue;
527  }
528 
529  //check against atlas feature intersection
530  if ( mFilterToAtlasIntersection )
531  {
532  if ( !f.hasGeometry() || !atlasGeometryEngine )
533  {
534  continue;
535  }
536 
537  if ( !atlasGeometryEngine->intersects( f.geometry().constGet() ) )
538  continue;
539  }
540 
541  QgsLayoutTableRow currentRow;
542  currentRow.reserve( mColumns.count() );
543 
544  for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
545  {
546  int idx = layer->fields().lookupField( column->attribute() );
547  if ( idx != -1 )
548  {
549  currentRow << replaceWrapChar( f.attributes().at( idx ) );
550  }
551  else
552  {
553  // Lets assume it's an expression
554  std::unique_ptr< QgsExpression > expression = qgis::make_unique< QgsExpression >( column->attribute() );
555  context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "row_number" ), counter + 1, true ) );
556  expression->prepare( &context );
557  QVariant value = expression->evaluate( &context );
558  currentRow << value;
559  }
560  }
561 
562  if ( !mShowUniqueRowsOnly || !contentsContainsRow( contents, currentRow ) )
563  {
564  contents << currentRow;
565  ++counter;
566  }
567  }
568 
569  //sort the list, starting with the last attribute
570  QgsLayoutAttributeTableCompare c;
571  QVector< QPair<int, bool> > sortColumns = sortAttributes();
572  for ( int i = sortColumns.size() - 1; i >= 0; --i )
573  {
574  c.setSortColumn( sortColumns.at( i ).first );
575  c.setAscending( sortColumns.at( i ).second );
576  std::stable_sort( contents.begin(), contents.end(), c );
577  }
578 
580  return true;
581 }
582 
584 {
586 
587  if ( mSource == LayerAttributes )
588  {
589  context.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer.get() ) );
590  }
591 
592  return context;
593 }
594 
596 {
598  if ( !mMap && !mMapUuid.isEmpty() && mLayout )
599  {
600  mMap = qobject_cast< QgsLayoutItemMap *>( mLayout->itemByUuid( mMapUuid, true ) );
601  if ( mMap )
602  {
603  //if we have found a valid map item, listen out to extent changes on it and refresh the table
606  }
607  }
608 }
609 
611 {
613 
616  {
617  mDataDefinedVectorLayer = nullptr;
618 
619  QString currentLayerIdentifier;
620  if ( QgsVectorLayer *currentLayer = mVectorLayer.get() )
621  currentLayerIdentifier = currentLayer->id();
622 
623  const QString layerIdentifier = mDataDefinedProperties.valueAsString( QgsLayoutObject::AttributeTableSourceLayer, context, currentLayerIdentifier );
624  QgsVectorLayer *ddLayer = qobject_cast< QgsVectorLayer * >( QgsLayoutUtils::mapLayerFromString( layerIdentifier, mLayout->project() ) );
625  if ( ddLayer )
626  mDataDefinedVectorLayer = ddLayer;
627  }
628 
630 }
631 
632 QVariant QgsLayoutItemAttributeTable::replaceWrapChar( const QVariant &variant ) const
633 {
634  //avoid converting variants to string if not required (try to maintain original type for sorting)
635  if ( mWrapString.isEmpty() || !variant.toString().contains( mWrapString ) )
636  return variant;
637 
638  QString replaced = variant.toString();
639  replaced.replace( mWrapString, QLatin1String( "\n" ) );
640  return replaced;
641 }
642 
644 {
645  switch ( mSource )
646  {
648  return mLayout->reportContext().layer();
650  {
651  if ( mDataDefinedVectorLayer )
652  return mDataDefinedVectorLayer;
653  else
654  return mVectorLayer.get();
655  }
657  {
658  QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
659  return relation.referencingLayer();
660  }
661  }
662  return nullptr;
663 }
664 
665 void QgsLayoutItemAttributeTable::removeLayer( const QString &layerId )
666 {
667  if ( mVectorLayer && mSource == QgsLayoutItemAttributeTable::LayerAttributes )
668  {
669  if ( layerId == mVectorLayer->id() )
670  {
671  mVectorLayer.setLayer( nullptr );
672  //remove existing columns
673  qDeleteAll( mColumns );
674  mColumns.clear();
675  }
676  }
677 }
678 
679 static bool columnsBySortRank( QPair<int, QgsLayoutTableColumn * > a, QPair<int, QgsLayoutTableColumn * > b )
680 {
681  return a.second->sortByRank() < b.second->sortByRank();
682 }
683 
684 QVector<QPair<int, bool> > QgsLayoutItemAttributeTable::sortAttributes() const
685 {
686  //generate list of all sorted columns
687  QVector< QPair<int, QgsLayoutTableColumn * > > sortedColumns;
688  int idx = 0;
689  for ( QgsLayoutTableColumn *column : mColumns )
690  {
691  if ( column->sortByRank() > 0 )
692  {
693  sortedColumns.append( qMakePair( idx, column ) );
694  }
695  idx++;
696  }
697 
698  //sort columns by rank
699  std::sort( sortedColumns.begin(), sortedColumns.end(), columnsBySortRank );
700 
701  //generate list of column index, bool for sort direction (to match 2.0 api)
702  QVector<QPair<int, bool> > attributesBySortRank;
703  attributesBySortRank.reserve( sortedColumns.size() );
704  for ( auto &column : qgis::as_const( sortedColumns ) )
705  {
706  attributesBySortRank.append( qMakePair( column.first,
707  column.second->sortOrder() == Qt::AscendingOrder ) );
708  }
709  return attributesBySortRank;
710 }
711 
713 {
714  if ( wrapString == mWrapString )
715  {
716  return;
717  }
718 
719  mWrapString = wrapString;
721  emit changed();
722 }
723 
724 bool QgsLayoutItemAttributeTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
725 {
726  if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
727  return false;
728 
729  tableElem.setAttribute( QStringLiteral( "source" ), QString::number( static_cast< int >( mSource ) ) );
730  tableElem.setAttribute( QStringLiteral( "relationId" ), mRelationId );
731  tableElem.setAttribute( QStringLiteral( "showUniqueRowsOnly" ), mShowUniqueRowsOnly );
732  tableElem.setAttribute( QStringLiteral( "showOnlyVisibleFeatures" ), mShowOnlyVisibleFeatures );
733  tableElem.setAttribute( QStringLiteral( "filterToAtlasIntersection" ), mFilterToAtlasIntersection );
734  tableElem.setAttribute( QStringLiteral( "maxFeatures" ), mMaximumNumberOfFeatures );
735  tableElem.setAttribute( QStringLiteral( "filterFeatures" ), mFilterFeatures ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
736  tableElem.setAttribute( QStringLiteral( "featureFilter" ), mFeatureFilter );
737  tableElem.setAttribute( QStringLiteral( "wrapString" ), mWrapString );
738 
739  if ( mMap )
740  {
741  tableElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
742  }
743 
744  if ( mVectorLayer )
745  {
746  tableElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer.layerId );
747  tableElem.setAttribute( QStringLiteral( "vectorLayerName" ), mVectorLayer.name );
748  tableElem.setAttribute( QStringLiteral( "vectorLayerSource" ), mVectorLayer.source );
749  tableElem.setAttribute( QStringLiteral( "vectorLayerProvider" ), mVectorLayer.provider );
750  }
751  return true;
752 }
753 
754 bool QgsLayoutItemAttributeTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
755 {
756  QgsVectorLayer *prevLayer = sourceLayer();
757  if ( prevLayer )
758  {
759  //disconnect from previous layer
760  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
761  }
762 
763  if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
764  return false;
765 
766  mSource = QgsLayoutItemAttributeTable::ContentSource( itemElem.attribute( QStringLiteral( "source" ), QStringLiteral( "0" ) ).toInt() );
767  mRelationId = itemElem.attribute( QStringLiteral( "relationId" ), QString() );
768 
770  {
771  mCurrentAtlasLayer = mLayout->reportContext().layer();
772  }
773 
774  mShowUniqueRowsOnly = itemElem.attribute( QStringLiteral( "showUniqueRowsOnly" ), QStringLiteral( "0" ) ).toInt();
775  mShowOnlyVisibleFeatures = itemElem.attribute( QStringLiteral( "showOnlyVisibleFeatures" ), QStringLiteral( "1" ) ).toInt();
776  mFilterToAtlasIntersection = itemElem.attribute( QStringLiteral( "filterToAtlasIntersection" ), QStringLiteral( "0" ) ).toInt();
777  mFilterFeatures = itemElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
778  mFeatureFilter = itemElem.attribute( QStringLiteral( "featureFilter" ), QString() );
779  mMaximumNumberOfFeatures = itemElem.attribute( QStringLiteral( "maxFeatures" ), QStringLiteral( "5" ) ).toInt();
780  mWrapString = itemElem.attribute( QStringLiteral( "wrapString" ) );
781 
782  //map
783  mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
784  if ( mMap )
785  {
788  mMap = nullptr;
789  }
790  // setting new mMap occurs in finalizeRestoreFromXml
791 
792  //vector layer
793  QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
794  QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
795  QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
796  QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
797  mVectorLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
798  mVectorLayer.resolveWeakly( mLayout->project() );
799 
800  //connect to new layer
802 
804 
805  emit changed();
806  return true;
807 }
808 
810 {
811  if ( source == mSource )
812  {
813  return;
814  }
815 
816  QgsVectorLayer *prevLayer = sourceLayer();
817  mSource = source;
818  QgsVectorLayer *newLayer = sourceLayer();
819 
820  if ( newLayer != prevLayer )
821  {
822  //disconnect from previous layer
823  if ( prevLayer )
824  {
825  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
826  }
827 
828  //connect to new layer
831  {
832  mCurrentAtlasLayer = newLayer;
833  }
834 
835  //layer has changed as a result of the source change, so reset column list
836  resetColumns();
837  }
838 
840  emit changed();
841 }
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:40
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:425
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:57
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
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...
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...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void extentChanged()
Is 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...
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:435
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
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:106
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.
bool contentsContainsRow(const QgsLayoutTableContents &contents, const QgsLayoutTableRow &row) const
Checks whether a table contents contains a given row.
ContentSource source() const
Returns the source for attributes shown in the table body.
TYPE * get() const
Returns a pointer to the layer, or nullptr if the reference has not yet been matched to a layer...
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
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
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.
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.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
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
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsVectorLayer * sourceLayer() const
Returns the source layer for the table, considering the table source mode.
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
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.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
Reads and writes project states.
Definition: qgsproject.h:89
A layout table subclass that displays attributes from a vector layer.
virtual QString uuid() const
Returns the item identification string.
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
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:320
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.
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
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.
void setVectorLayer(QgsVectorLayer *layer)
Sets the vector layer from which to display feature attributes.
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else...
void mapRotationChanged(double newRotation)
Is 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.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Definition: qgsrectangle.h:311
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
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.
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.
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.
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Class for doing transforms between two map coordinate systems.
QgsLayoutItemMap * map() const
Returns the layout map whose extents are controlling the features shown in the table.
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
Query the layer for features specified in request.
QString relationId() const
Returns the relation id which the table displays child features from.
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
const QgsLayout * layout() const
Returns the layout the object is attached to.
ContentSource
Specifies the content source for the attribute table.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
QVector< QPair< int, bool > > sortAttributes() const
Returns the attributes used to sort the table&#39;s features.
void changed()
Emitted when the object&#39;s properties change.
Represents a vector layer which manages a vector based data sets.
QString wrapString() const
Returns the string used to wrap the contents of the table cells by.
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()
This signal is emitted when modifications has been done on layer.
QPolygonF visibleExtentPolygon() const
Returns a polygon representing the current visible map extent, considering map extents and rotation...
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:70
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...