QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 
228 void QgsLayoutItemAttributeTable::disconnectCurrentMap()
229 {
230  if ( !mMap )
231  {
232  return;
233  }
234 
237  disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemAttributeTable::disconnectCurrentMap );
238  mMap = nullptr;
239 }
240 
242 {
243  if ( map == mMap )
244  {
245  //no change
246  return;
247  }
248  disconnectCurrentMap();
249 
250  mMap = map;
251  if ( mMap )
252  {
253  //listen out for extent changes in linked map
256  connect( mMap, &QObject::destroyed, this, &QgsLayoutItemAttributeTable::disconnectCurrentMap );
257  }
259  emit changed();
260 }
261 
263 {
264  if ( features == mMaximumNumberOfFeatures )
265  {
266  return;
267  }
268 
269  mMaximumNumberOfFeatures = features;
271  emit changed();
272 }
273 
275 {
276  if ( uniqueOnly == mShowUniqueRowsOnly )
277  {
278  return;
279  }
280 
281  mShowUniqueRowsOnly = uniqueOnly;
283  emit changed();
284 }
285 
287 {
288  if ( visibleOnly == mShowOnlyVisibleFeatures )
289  {
290  return;
291  }
292 
293  mShowOnlyVisibleFeatures = visibleOnly;
295  emit changed();
296 }
297 
299 {
300  if ( filterToAtlas == mFilterToAtlasIntersection )
301  {
302  return;
303  }
304 
305  mFilterToAtlasIntersection = filterToAtlas;
307  emit changed();
308 }
309 
311 {
312  if ( filter == mFilterFeatures )
313  {
314  return;
315  }
316 
317  mFilterFeatures = filter;
319  emit changed();
320 }
321 
322 void QgsLayoutItemAttributeTable::setFeatureFilter( const QString &expression )
323 {
324  if ( expression == mFeatureFilter )
325  {
326  return;
327  }
328 
329  mFeatureFilter = expression;
331  emit changed();
332 }
333 
334 void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields, bool refresh )
335 {
337  if ( !source )
338  {
339  return;
340  }
341 
342  //rebuild columns list, taking only fields contained in supplied list
343  qDeleteAll( mColumns );
344  mColumns.clear();
345 
346  const QgsFields layerFields = source->fields();
347 
348  if ( !fields.isEmpty() )
349  {
350  for ( const QString &field : fields )
351  {
352  int attrIdx = layerFields.lookupField( field );
353  if ( attrIdx < 0 )
354  continue;
355 
356  QString currentAlias = source->attributeDisplayName( attrIdx );
357  std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
358  col->setAttribute( layerFields.at( attrIdx ).name() );
359  col->setHeading( currentAlias );
360  mColumns.append( col.release() );
361  }
362  }
363  else
364  {
365  //resetting, so add all attributes to columns
366  int idx = 0;
367  for ( const QgsField &field : layerFields )
368  {
369  QString currentAlias = source->attributeDisplayName( idx );
370  std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
371  col->setAttribute( field.name() );
372  col->setHeading( currentAlias );
373  mColumns.append( col.release() );
374  idx++;
375  }
376  }
377 
378  if ( refresh )
379  {
381  }
382 }
383 
384 void QgsLayoutItemAttributeTable::restoreFieldAliasMap( const QMap<int, QString> &map )
385 {
387  if ( !source )
388  {
389  return;
390  }
391 
392  for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
393  {
394  int attrIdx = source->fields().lookupField( column->attribute() );
395  if ( map.contains( attrIdx ) )
396  {
397  column->setHeading( map.value( attrIdx ) );
398  }
399  else
400  {
401  column->setHeading( source->attributeDisplayName( attrIdx ) );
402  }
403  }
404 }
405 
407 {
408  contents.clear();
409 
410  QgsVectorLayer *layer = sourceLayer();
411  if ( !layer )
412  {
413  //no source layer
414  return false;
415  }
416 
418  context.setFields( layer->fields() );
419 
420  QgsFeatureRequest req;
421 
422  //prepare filter expression
423  std::unique_ptr<QgsExpression> filterExpression;
424  bool activeFilter = false;
425  if ( mFilterFeatures && !mFeatureFilter.isEmpty() )
426  {
427  filterExpression = qgis::make_unique< QgsExpression >( mFeatureFilter );
428  if ( !filterExpression->hasParserError() )
429  {
430  activeFilter = true;
431  req.setFilterExpression( mFeatureFilter );
432  req.setExpressionContext( context );
433  }
434  }
435 
436  QgsRectangle selectionRect;
437  QgsGeometry visibleRegion;
438  std::unique_ptr< QgsGeometryEngine > visibleMapEngine;
439  if ( mMap && mShowOnlyVisibleFeatures )
440  {
441  visibleRegion = QgsGeometry::fromQPolygonF( mMap->visibleExtentPolygon() );
442  selectionRect = visibleRegion.boundingBox();
443  if ( layer )
444  {
445  //transform back to layer CRS
446  QgsCoordinateTransform coordTransform( layer->crs(), mMap->crs(), mLayout->project() );
447  try
448  {
449  selectionRect = coordTransform.transformBoundingBox( selectionRect, QgsCoordinateTransform::ReverseTransform );
450  visibleRegion.transform( coordTransform, QgsCoordinateTransform::ReverseTransform );
451  }
452  catch ( QgsCsException &cse )
453  {
454  Q_UNUSED( cse )
455  return false;
456  }
457  }
458  visibleMapEngine.reset( QgsGeometry::createGeometryEngine( visibleRegion.constGet() ) );
459  visibleMapEngine->prepareGeometry();
460  }
461 
462  QgsGeometry atlasGeometry;
463  std::unique_ptr< QgsGeometryEngine > atlasGeometryEngine;
464  if ( mFilterToAtlasIntersection )
465  {
466  atlasGeometry = mLayout->reportContext().currentGeometry( layer->crs() );
467  if ( !atlasGeometry.isNull() )
468  {
469  if ( selectionRect.isNull() )
470  {
471  selectionRect = atlasGeometry.boundingBox();
472  }
473  else
474  {
475  selectionRect = selectionRect.intersect( atlasGeometry.boundingBox() );
476  }
477 
478  atlasGeometryEngine.reset( QgsGeometry::createGeometryEngine( atlasGeometry.constGet() ) );
479  atlasGeometryEngine->prepareGeometry();
480  }
481  }
482 
484  {
485  QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
486  QgsFeature atlasFeature = mLayout->reportContext().feature();
487  req = relation.getRelatedFeaturesRequest( atlasFeature );
488  }
489 
490  if ( !selectionRect.isEmpty() )
491  req.setFilterRect( selectionRect );
492 
493  req.setFlags( mShowOnlyVisibleFeatures ? QgsFeatureRequest::ExactIntersect : QgsFeatureRequest::NoFlags );
494 
496  {
497  //source mode is current atlas feature
498  QgsFeature atlasFeature = mLayout->reportContext().feature();
499  req.setFilterFid( atlasFeature.id() );
500  }
501 
502  QgsFeature f;
503  int counter = 0;
504  QgsFeatureIterator fit = layer->getFeatures( req );
505 
506  while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
507  {
508  context.setFeature( f );
509  //check feature against filter
510  if ( activeFilter && filterExpression )
511  {
512  QVariant result = filterExpression->evaluate( &context );
513  // skip this feature if the filter evaluation is false
514  if ( !result.toBool() )
515  {
516  continue;
517  }
518  }
519 
520  // check against exact map bounds
521  if ( visibleMapEngine )
522  {
523  if ( !f.hasGeometry() )
524  continue;
525 
526  if ( !visibleMapEngine->intersects( f.geometry().constGet() ) )
527  continue;
528  }
529 
530  //check against atlas feature intersection
531  if ( mFilterToAtlasIntersection )
532  {
533  if ( !f.hasGeometry() || !atlasGeometryEngine )
534  {
535  continue;
536  }
537 
538  if ( !atlasGeometryEngine->intersects( f.geometry().constGet() ) )
539  continue;
540  }
541 
542  QgsLayoutTableRow currentRow;
543  currentRow.reserve( mColumns.count() );
544 
545  for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
546  {
547  int idx = layer->fields().lookupField( column->attribute() );
548  if ( idx != -1 )
549  {
550  currentRow << replaceWrapChar( f.attributes().at( idx ) );
551  }
552  else
553  {
554  // Lets assume it's an expression
555  std::unique_ptr< QgsExpression > expression = qgis::make_unique< QgsExpression >( column->attribute() );
556  context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "row_number" ), counter + 1, true ) );
557  expression->prepare( &context );
558  QVariant value = expression->evaluate( &context );
559  currentRow << value;
560  }
561  }
562 
563  if ( !mShowUniqueRowsOnly || !contentsContainsRow( contents, currentRow ) )
564  {
565  contents << currentRow;
566  ++counter;
567  }
568  }
569 
570  //sort the list, starting with the last attribute
571  QgsLayoutAttributeTableCompare c;
572  QVector< QPair<int, bool> > sortColumns = sortAttributes();
573  for ( int i = sortColumns.size() - 1; i >= 0; --i )
574  {
575  c.setSortColumn( sortColumns.at( i ).first );
576  c.setAscending( sortColumns.at( i ).second );
577  std::stable_sort( contents.begin(), contents.end(), c );
578  }
579 
581  return true;
582 }
583 
585 {
587 
588  if ( mSource == LayerAttributes )
589  {
590  context.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer.get() ) );
591  }
592 
593  return context;
594 }
595 
597 {
599  if ( !mMap && !mMapUuid.isEmpty() && mLayout )
600  {
601  mMap = qobject_cast< QgsLayoutItemMap *>( mLayout->itemByUuid( mMapUuid, true ) );
602  if ( mMap )
603  {
604  //if we have found a valid map item, listen out to extent changes on it and refresh the table
607  }
608  }
609 }
610 
612 {
614 
617  {
618  mDataDefinedVectorLayer = nullptr;
619 
620  QString currentLayerIdentifier;
621  if ( QgsVectorLayer *currentLayer = mVectorLayer.get() )
622  currentLayerIdentifier = currentLayer->id();
623 
624  const QString layerIdentifier = mDataDefinedProperties.valueAsString( QgsLayoutObject::AttributeTableSourceLayer, context, currentLayerIdentifier );
625  QgsVectorLayer *ddLayer = qobject_cast< QgsVectorLayer * >( QgsLayoutUtils::mapLayerFromString( layerIdentifier, mLayout->project() ) );
626  if ( ddLayer )
627  mDataDefinedVectorLayer = ddLayer;
628  }
629 
631 }
632 
633 QVariant QgsLayoutItemAttributeTable::replaceWrapChar( const QVariant &variant ) const
634 {
635  //avoid converting variants to string if not required (try to maintain original type for sorting)
636  if ( mWrapString.isEmpty() || !variant.toString().contains( mWrapString ) )
637  return variant;
638 
639  QString replaced = variant.toString();
640  replaced.replace( mWrapString, QLatin1String( "\n" ) );
641  return replaced;
642 }
643 
645 {
646  switch ( mSource )
647  {
649  return mLayout->reportContext().layer();
651  {
652  if ( mDataDefinedVectorLayer )
653  return mDataDefinedVectorLayer;
654  else
655  return mVectorLayer.get();
656  }
658  {
659  QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
660  return relation.referencingLayer();
661  }
662  }
663  return nullptr;
664 }
665 
666 void QgsLayoutItemAttributeTable::removeLayer( const QString &layerId )
667 {
668  if ( mVectorLayer && mSource == QgsLayoutItemAttributeTable::LayerAttributes )
669  {
670  if ( layerId == mVectorLayer->id() )
671  {
672  mVectorLayer.setLayer( nullptr );
673  //remove existing columns
674  qDeleteAll( mColumns );
675  mColumns.clear();
676  }
677  }
678 }
679 
680 static bool columnsBySortRank( QPair<int, QgsLayoutTableColumn * > a, QPair<int, QgsLayoutTableColumn * > b )
681 {
682  return a.second->sortByRank() < b.second->sortByRank();
683 }
684 
685 QVector<QPair<int, bool> > QgsLayoutItemAttributeTable::sortAttributes() const
686 {
687  //generate list of all sorted columns
688  QVector< QPair<int, QgsLayoutTableColumn * > > sortedColumns;
689  int idx = 0;
690  for ( QgsLayoutTableColumn *column : mColumns )
691  {
692  if ( column->sortByRank() > 0 )
693  {
694  sortedColumns.append( qMakePair( idx, column ) );
695  }
696  idx++;
697  }
698 
699  //sort columns by rank
700  std::sort( sortedColumns.begin(), sortedColumns.end(), columnsBySortRank );
701 
702  //generate list of column index, bool for sort direction (to match 2.0 api)
703  QVector<QPair<int, bool> > attributesBySortRank;
704  attributesBySortRank.reserve( sortedColumns.size() );
705  for ( auto &column : qgis::as_const( sortedColumns ) )
706  {
707  attributesBySortRank.append( qMakePair( column.first,
708  column.second->sortOrder() == Qt::AscendingOrder ) );
709  }
710  return attributesBySortRank;
711 }
712 
714 {
715  if ( wrapString == mWrapString )
716  {
717  return;
718  }
719 
720  mWrapString = wrapString;
722  emit changed();
723 }
724 
725 bool QgsLayoutItemAttributeTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
726 {
727  if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
728  return false;
729 
730  tableElem.setAttribute( QStringLiteral( "source" ), QString::number( static_cast< int >( mSource ) ) );
731  tableElem.setAttribute( QStringLiteral( "relationId" ), mRelationId );
732  tableElem.setAttribute( QStringLiteral( "showUniqueRowsOnly" ), mShowUniqueRowsOnly );
733  tableElem.setAttribute( QStringLiteral( "showOnlyVisibleFeatures" ), mShowOnlyVisibleFeatures );
734  tableElem.setAttribute( QStringLiteral( "filterToAtlasIntersection" ), mFilterToAtlasIntersection );
735  tableElem.setAttribute( QStringLiteral( "maxFeatures" ), mMaximumNumberOfFeatures );
736  tableElem.setAttribute( QStringLiteral( "filterFeatures" ), mFilterFeatures ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
737  tableElem.setAttribute( QStringLiteral( "featureFilter" ), mFeatureFilter );
738  tableElem.setAttribute( QStringLiteral( "wrapString" ), mWrapString );
739 
740  if ( mMap )
741  {
742  tableElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
743  }
744 
745  if ( mVectorLayer )
746  {
747  tableElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer.layerId );
748  tableElem.setAttribute( QStringLiteral( "vectorLayerName" ), mVectorLayer.name );
749  tableElem.setAttribute( QStringLiteral( "vectorLayerSource" ), mVectorLayer.source );
750  tableElem.setAttribute( QStringLiteral( "vectorLayerProvider" ), mVectorLayer.provider );
751  }
752  return true;
753 }
754 
755 bool QgsLayoutItemAttributeTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
756 {
757  QgsVectorLayer *prevLayer = sourceLayer();
758  if ( prevLayer )
759  {
760  //disconnect from previous layer
761  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
762  }
763 
764  if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
765  return false;
766 
767  mSource = QgsLayoutItemAttributeTable::ContentSource( itemElem.attribute( QStringLiteral( "source" ), QStringLiteral( "0" ) ).toInt() );
768  mRelationId = itemElem.attribute( QStringLiteral( "relationId" ), QString() );
769 
771  {
772  mCurrentAtlasLayer = mLayout->reportContext().layer();
773  }
774 
775  mShowUniqueRowsOnly = itemElem.attribute( QStringLiteral( "showUniqueRowsOnly" ), QStringLiteral( "0" ) ).toInt();
776  mShowOnlyVisibleFeatures = itemElem.attribute( QStringLiteral( "showOnlyVisibleFeatures" ), QStringLiteral( "1" ) ).toInt();
777  mFilterToAtlasIntersection = itemElem.attribute( QStringLiteral( "filterToAtlasIntersection" ), QStringLiteral( "0" ) ).toInt();
778  mFilterFeatures = itemElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
779  mFeatureFilter = itemElem.attribute( QStringLiteral( "featureFilter" ), QString() );
780  mMaximumNumberOfFeatures = itemElem.attribute( QStringLiteral( "maxFeatures" ), QStringLiteral( "5" ) ).toInt();
781  mWrapString = itemElem.attribute( QStringLiteral( "wrapString" ) );
782 
783  //map
784  mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
785  if ( mMap )
786  {
789  mMap = nullptr;
790  }
791  // setting new mMap occurs in finalizeRestoreFromXml
792 
793  //vector layer
794  QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
795  QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
796  QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
797  QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
798  mVectorLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
799  mVectorLayer.resolveWeakly( mLayout->project() );
800 
801  //connect to new layer
803 
805 
806  emit changed();
807  return true;
808 }
809 
811 {
812  if ( source == mSource )
813  {
814  return;
815  }
816 
817  QgsVectorLayer *prevLayer = sourceLayer();
818  mSource = source;
819  QgsVectorLayer *newLayer = sourceLayer();
820 
821  if ( newLayer != prevLayer )
822  {
823  //disconnect from previous layer
824  if ( prevLayer )
825  {
826  disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
827  }
828 
829  //connect to new layer
832  {
833  mCurrentAtlasLayer = newLayer;
834  }
835 
836  //layer has changed as a result of the source change, so reset column list
837  resetColumns();
838  }
839 
841  emit changed();
842 }
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.
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:122
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:222
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:154
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.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
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:86
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
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...