QGIS API Documentation 3.28.14-Firenze (exported)
Loading...
Searching...
No Matches
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"
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 "qgsfieldformatter.h"
30#include "qgsgeometry.h"
31#include "qgsexception.h"
32#include "qgsmapsettings.h"
35#include "qgsgeometryengine.h"
36#include "qgsconditionalstyle.h"
37#include "qgsfontutils.h"
38#include "qgsvariantutils.h"
39
40//
41// QgsLayoutItemAttributeTable
42//
43
45 : QgsLayoutTable( layout )
46{
47 if ( mLayout )
48 {
49 connect( mLayout->project(), static_cast < void ( QgsProject::* )( const QString & ) >( &QgsProject::layerWillBeRemoved ), this, &QgsLayoutItemAttributeTable::removeLayer );
50
51 //coverage layer change = regenerate columns
52 connect( &mLayout->reportContext(), &QgsLayoutReportContext::layerChanged, this, &QgsLayoutItemAttributeTable::atlasLayerChanged );
53 }
55}
56
61
63{
64 return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemTable.svg" ) );
65}
66
71
73{
74 return tr( "<Attribute table frame>" );
75}
76
78{
79 if ( layer == mVectorLayer.get() )
80 {
81 //no change
82 return;
83 }
84
85 QgsVectorLayer *prevLayer = sourceLayer();
86 mVectorLayer.setLayer( layer );
87
88 if ( mSource == QgsLayoutItemAttributeTable::LayerAttributes && layer != prevLayer )
89 {
90 if ( prevLayer )
91 {
92 //disconnect from previous layer
94 }
95
96 //rebuild column list to match all columns from layer
98
99 //listen for modifications to layer and refresh table when they occur
100 connect( mVectorLayer.get(), &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
101 }
102
104 emit changed();
105}
106
107void QgsLayoutItemAttributeTable::setRelationId( const QString &relationId )
108{
109 if ( relationId == mRelationId )
110 {
111 //no change
112 return;
113 }
114
115 QgsVectorLayer *prevLayer = sourceLayer();
116 mRelationId = relationId;
117 QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
118 QgsVectorLayer *newLayer = relation.referencingLayer();
119
120 if ( mSource == QgsLayoutItemAttributeTable::RelationChildren && newLayer != prevLayer )
121 {
122 if ( prevLayer )
123 {
124 //disconnect from previous layer
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
133 }
134
136 emit changed();
137}
138
139void QgsLayoutItemAttributeTable::atlasLayerChanged( QgsVectorLayer *layer )
140{
141 if ( mSource != QgsLayoutItemAttributeTable::AtlasFeature || layer == mCurrentAtlasLayer )
142 {
143 //nothing to do
144 return;
145 }
146
147 //atlas feature mode, atlas layer changed, so we need to reset columns
148 if ( mCurrentAtlasLayer )
149 {
150 //disconnect from previous layer
151 disconnect( mCurrentAtlasLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
152 }
153
154 const bool mustRebuildColumns = static_cast< bool >( mCurrentAtlasLayer ) || mColumns.empty();
155 mCurrentAtlasLayer = layer;
156
157 if ( mustRebuildColumns )
158 {
159 //rebuild column list to match all columns from layer
160 resetColumns();
161 }
162
164
165 //listen for modifications to layer and refresh table when they occur
167}
168
170{
172 if ( !source )
173 {
174 return;
175 }
176
177 //remove existing columns
178 mColumns.clear();
179 mSortColumns.clear();
180
181 //rebuild columns list from vector layer fields
182 int idx = 0;
183 const QgsFields sourceFields = source->fields();
184
185 for ( const auto &field : sourceFields )
186 {
187 QString currentAlias = source->attributeDisplayName( idx );
189 col.setAttribute( field.name() );
190 col.setHeading( currentAlias );
191 mColumns.append( col );
192 idx++;
193 }
194}
195
196void QgsLayoutItemAttributeTable::disconnectCurrentMap()
197{
198 if ( !mMap )
199 {
200 return;
201 }
202
205 disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemAttributeTable::disconnectCurrentMap );
206 mMap = nullptr;
207}
208
210{
211 return mUseConditionalStyling;
212}
213
215{
216 if ( useConditionalStyling == mUseConditionalStyling )
217 {
218 return;
219 }
220
221 mUseConditionalStyling = useConditionalStyling;
223 emit changed();
224}
225
227{
228 if ( map == mMap )
229 {
230 //no change
231 return;
232 }
233 disconnectCurrentMap();
234
235 mMap = map;
236 if ( mMap )
237 {
238 //listen out for extent changes in linked map
241 }
243 emit changed();
244}
245
247{
248 if ( features == mMaximumNumberOfFeatures )
249 {
250 return;
251 }
252
253 mMaximumNumberOfFeatures = features;
255 emit changed();
256}
257
259{
260 if ( uniqueOnly == mShowUniqueRowsOnly )
261 {
262 return;
263 }
264
265 mShowUniqueRowsOnly = uniqueOnly;
267 emit changed();
268}
269
271{
272 if ( visibleOnly == mShowOnlyVisibleFeatures )
273 {
274 return;
275 }
276
277 mShowOnlyVisibleFeatures = visibleOnly;
279 emit changed();
280}
281
283{
284 if ( filterToAtlas == mFilterToAtlasIntersection )
285 {
286 return;
287 }
288
289 mFilterToAtlasIntersection = filterToAtlas;
291 emit changed();
292}
293
295{
296 if ( filter == mFilterFeatures )
297 {
298 return;
299 }
300
301 mFilterFeatures = filter;
303 emit changed();
304}
305
306void QgsLayoutItemAttributeTable::setFeatureFilter( const QString &expression )
307{
308 if ( expression == mFeatureFilter )
309 {
310 return;
311 }
312
313 mFeatureFilter = expression;
315 emit changed();
316}
317
318void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields, bool refresh )
319{
321 if ( !source )
322 {
323 return;
324 }
325
326 //rebuild columns list, taking only fields contained in supplied list
327 mColumns.clear();
328
329 const QgsFields layerFields = source->fields();
330
331 if ( !fields.isEmpty() )
332 {
333 for ( const QString &field : fields )
334 {
335 int attrIdx = layerFields.lookupField( field );
336 if ( attrIdx < 0 )
337 {
338 continue;
339 }
340 QString currentAlias = source->attributeDisplayName( attrIdx );
342 col.setAttribute( layerFields.at( attrIdx ).name() );
343 col.setHeading( currentAlias );
344 mColumns.append( col );
345 }
346 }
347 else
348 {
349 //resetting, so add all attributes to columns
350 int idx = 0;
351 for ( const QgsField &field : layerFields )
352 {
353 QString currentAlias = source->attributeDisplayName( idx );
355 col.setAttribute( field.name() );
356 col.setHeading( currentAlias );
357 mColumns.append( col );
358 idx++;
359 }
360 }
361
362 if ( refresh )
363 {
365 }
366}
367
368void QgsLayoutItemAttributeTable::restoreFieldAliasMap( const QMap<int, QString> &map )
369{
371 if ( !source )
372 {
373 return;
374 }
375
376 for ( int i = 0; i < mColumns.count(); i++ )
377 {
378 int attrIdx = source->fields().lookupField( mColumns[i].attribute() );
379 if ( map.contains( attrIdx ) )
380 {
381 mColumns[i].setHeading( map.value( attrIdx ) );
382 }
383 else
384 {
385 mColumns[i].setHeading( source->attributeDisplayName( attrIdx ) );
386 }
387 }
388}
389
391{
392 contents.clear();
393 mLayerCache.clear();
394
395 QgsVectorLayer *layer = sourceLayer();
396 if ( !layer )
397 {
398 //no source layer
399 return false;
400 }
401
402 const QgsConditionalLayerStyles *conditionalStyles = layer->conditionalStyles();
403
405 context.setFields( layer->fields() );
406
408 req.setExpressionContext( context );
409
410 //prepare filter expression
411 std::unique_ptr<QgsExpression> filterExpression;
412 bool activeFilter = false;
413 if ( mFilterFeatures && !mFeatureFilter.isEmpty() )
414 {
415 filterExpression = std::make_unique< QgsExpression >( mFeatureFilter );
416 if ( !filterExpression->hasParserError() )
417 {
418 activeFilter = true;
419 req.setFilterExpression( mFeatureFilter );
420 }
421 }
422
423#ifdef HAVE_SERVER_PYTHON_PLUGINS
424 if ( mLayout->renderContext().featureFilterProvider() )
425 {
426 mLayout->renderContext().featureFilterProvider()->filterFeatures( layer, req );
427 }
428#endif
429
430 QgsRectangle selectionRect;
431 QgsGeometry visibleRegion;
432 std::unique_ptr< QgsGeometryEngine > visibleMapEngine;
433 if ( mMap && mShowOnlyVisibleFeatures )
434 {
435 visibleRegion = QgsGeometry::fromQPolygonF( mMap->visibleExtentPolygon() );
436 selectionRect = visibleRegion.boundingBox();
437 //transform back to layer CRS
438 const QgsCoordinateTransform coordTransform( layer->crs(), mMap->crs(), mLayout->project() );
439 QgsCoordinateTransform extentTransform = coordTransform;
440 extentTransform.setBallparkTransformsAreAppropriate( true );
441 try
442 {
443 selectionRect = extentTransform.transformBoundingBox( selectionRect, Qgis::TransformDirection::Reverse );
444 visibleRegion.transform( coordTransform, Qgis::TransformDirection::Reverse );
445 }
446 catch ( QgsCsException &cse )
447 {
448 Q_UNUSED( cse )
449 return false;
450 }
451 visibleMapEngine.reset( QgsGeometry::createGeometryEngine( visibleRegion.constGet() ) );
452 visibleMapEngine->prepareGeometry();
453 }
454
455 QgsGeometry atlasGeometry;
456 std::unique_ptr< QgsGeometryEngine > atlasGeometryEngine;
457 if ( mFilterToAtlasIntersection )
458 {
459 atlasGeometry = mLayout->reportContext().currentGeometry( layer->crs() );
460 if ( !atlasGeometry.isNull() )
461 {
462 if ( selectionRect.isNull() )
463 {
464 selectionRect = atlasGeometry.boundingBox();
465 }
466 else
467 {
468 selectionRect = selectionRect.intersect( atlasGeometry.boundingBox() );
469 }
470
471 atlasGeometryEngine.reset( QgsGeometry::createGeometryEngine( atlasGeometry.constGet() ) );
472 atlasGeometryEngine->prepareGeometry();
473 }
474 }
475
477 {
478 QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
479 QgsFeature atlasFeature = mLayout->reportContext().feature();
480 req = relation.getRelatedFeaturesRequest( atlasFeature );
481 }
482
483 if ( !selectionRect.isEmpty() )
484 req.setFilterRect( selectionRect );
485
487
489 {
490 //source mode is current atlas feature
491 QgsFeature atlasFeature = mLayout->reportContext().feature();
492 req.setFilterFid( atlasFeature.id() );
493 }
494
495 for ( const QgsLayoutTableColumn &column : std::as_const( mSortColumns ) )
496 {
497 req.addOrderBy( column.attribute(), column.sortOrder() == Qt::AscendingOrder );
498 }
499
500 QgsFeature f;
501 int counter = 0;
502 QgsFeatureIterator fit = layer->getFeatures( req );
503
504 mConditionalStyles.clear();
505 mFeatures.clear();
506
507 QVector< QVector< Cell > > tempContents;
508 QgsLayoutTableContents existingContents;
509
510 while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
511 {
512 context.setFeature( f );
513 //check feature against filter
514 if ( activeFilter && filterExpression )
515 {
516 QVariant result = filterExpression->evaluate( &context );
517 // skip this feature if the filter evaluation is false
518 if ( !result.toBool() )
519 {
520 continue;
521 }
522 }
523
524 // check against exact map bounds
525 if ( visibleMapEngine )
526 {
527 if ( !f.hasGeometry() )
528 continue;
529
530 if ( !visibleMapEngine->intersects( f.geometry().constGet() ) )
531 continue;
532 }
533
534 //check against atlas feature intersection
535 if ( mFilterToAtlasIntersection )
536 {
537 if ( !f.hasGeometry() || !atlasGeometryEngine )
538 {
539 continue;
540 }
541
542 if ( !atlasGeometryEngine->intersects( f.geometry().constGet() ) )
543 continue;
544 }
545
546 QgsConditionalStyle rowStyle;
547
548 if ( mUseConditionalStyling )
549 {
550 const QList<QgsConditionalStyle> styles = QgsConditionalStyle::matchingConditionalStyles( conditionalStyles->rowStyles(), QVariant(), context );
551 rowStyle = QgsConditionalStyle::compressStyles( styles );
552 }
553
554 // We need to build up two different lists here -- one is a pair of the cell contents along with the cell style.
555 // We need this one because we do a sorting step later, and we need to ensure that the cell styling is attached to the right row and sorted
556 // correctly when this occurs
557 // We also need a list of just the cell contents, so that we can do a quick check for row uniqueness (when the
558 // corresponding option is enabled)
559 QVector< Cell > currentRow;
560#ifdef HAVE_SERVER_PYTHON_PLUGINS
561 mColumns = filteredColumns();
562#endif
563 currentRow.reserve( mColumns.count() );
564 QgsLayoutTableRow rowContents;
565 rowContents.reserve( mColumns.count() );
566
567 for ( const QgsLayoutTableColumn &column : std::as_const( mColumns ) )
568 {
570 int idx = layer->fields().lookupField( column.attribute() );
571 if ( idx != -1 )
572 {
573 QVariant val = f.attributes().at( idx );
574
575 if ( mUseConditionalStyling )
576 {
577 QList<QgsConditionalStyle> styles = conditionalStyles->fieldStyles( layer->fields().at( idx ).name() );
578 styles = QgsConditionalStyle::matchingConditionalStyles( styles, val, context );
579 styles.insert( 0, rowStyle );
580 style = QgsConditionalStyle::compressStyles( styles );
581 }
582
583 const QgsEditorWidgetSetup setup = layer->fields().at( idx ).editorWidgetSetup();
584
585 if ( ! setup.isNull() )
586 {
588 QVariant cache;
589
590 auto it = mLayerCache.constFind( column.attribute() );
591 if ( it != mLayerCache.constEnd() )
592 {
593 cache = it.value();
594 }
595 else
596 {
597 cache = fieldFormatter->createCache( layer, idx, setup.config() );
598 mLayerCache.insert( column.attribute(), cache );
599 }
600
601 val = fieldFormatter->representValue( layer, idx, setup.config(), cache, val );
602 }
603
604 QVariant v = QgsVariantUtils::isNull( val ) ? QString() : replaceWrapChar( val );
605 currentRow << Cell( v, style, f );
606 rowContents << v;
607 }
608 else
609 {
610 // Lets assume it's an expression
611 std::unique_ptr< QgsExpression > expression = std::make_unique< QgsExpression >( column.attribute() );
612 context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "row_number" ), counter + 1, true ) );
613 expression->prepare( &context );
614 QVariant value = expression->evaluate( &context );
615
616 currentRow << Cell( value, rowStyle, f );
617 rowContents << value;
618 }
619 }
620
621 if ( mShowUniqueRowsOnly )
622 {
623 if ( contentsContainsRow( existingContents, rowContents ) )
624 continue;
625 }
626
627 tempContents << currentRow;
628 existingContents << rowContents;
629 ++counter;
630 }
631
632 // build final table contents
633 contents.reserve( tempContents.size() );
634 mConditionalStyles.reserve( tempContents.size() );
635 mFeatures.reserve( tempContents.size() );
636 for ( auto it = tempContents.constBegin(); it != tempContents.constEnd(); ++it )
637 {
639 QList< QgsConditionalStyle > rowStyles;
640 row.reserve( it->size() );
641 rowStyles.reserve( it->size() );
642
643 for ( auto cellIt = it->constBegin(); cellIt != it->constEnd(); ++cellIt )
644 {
645 row << cellIt->content;
646 rowStyles << cellIt->style;
647 if ( cellIt == it->constBegin() )
648 mFeatures << cellIt->feature;
649 }
650 contents << row;
651 mConditionalStyles << rowStyles;
652 }
653
655 return true;
656}
657
659{
660 if ( row >= mConditionalStyles.size() )
661 return QgsConditionalStyle();
662
663 return mConditionalStyles.at( row ).at( column );
664}
665
667{
669
670 const QgsConditionalStyle style = conditionalCellStyle( row, column );
671 if ( style.isValid() )
672 {
673 // apply conditional style formatting to text format
674 const QFont styleFont = style.font();
675 if ( styleFont != QFont() )
676 {
677 QFont newFont = format.font();
678 // we want to keep all the other font settings, like word/letter spacing
679 newFont.setFamily( styleFont.family() );
680
681 // warning -- there's a potential trap here! We can't just read QFont::styleName(), as that may be blank even when
682 // the font has the bold or italic attributes set! Reading the style name via QFontInfo avoids this and always returns
683 // a correct style name
684 const QString styleName = QgsFontUtils::resolveFontStyleName( styleFont );
685 if ( !styleName.isEmpty() )
686 newFont.setStyleName( styleName );
687
688 newFont.setStrikeOut( styleFont.strikeOut() );
689 newFont.setUnderline( styleFont.underline() );
690 format.setFont( newFont );
691 if ( styleName.isEmpty() )
692 {
693 // we couldn't find a direct match for the conditional font's bold/italic settings as a font style name.
694 // This means the conditional style is using Qt's "faux bold/italic" mode. Even though it causes reduced quality font
695 // rendering, we'll apply it here anyway just to ensure that the rendered font styling matches the conditional style.
696 if ( styleFont.bold() )
697 format.setForcedBold( true );
698 if ( styleFont.italic() )
699 format.setForcedItalic( true );
700 }
701 }
702 }
703
704 return format;
705}
706
708{
709 std::unique_ptr< QgsExpressionContextScope >scope( QgsLayoutTable::scopeForCell( row, column ) );
710 scope->setFeature( mFeatures.value( row ) );
711 scope->setFields( scope->feature().fields() );
712 return scope.release();
713}
714
716{
718
719 if ( mSource == LayerAttributes )
720 {
721 context.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer.get() ) );
722 }
723
724 return context;
725}
726
728{
730 if ( !mMap && !mMapUuid.isEmpty() && mLayout )
731 {
732 mMap = qobject_cast< QgsLayoutItemMap *>( mLayout->itemByUuid( mMapUuid, true ) );
733 if ( mMap )
734 {
735 //if we have found a valid map item, listen out to extent changes on it and refresh the table
738 }
739 }
740}
741
743{
745
748 {
749 mDataDefinedVectorLayer = nullptr;
750
751 QString currentLayerIdentifier;
752 if ( QgsVectorLayer *currentLayer = mVectorLayer.get() )
753 currentLayerIdentifier = currentLayer->id();
754
755 const QString layerIdentifier = mDataDefinedProperties.valueAsString( QgsLayoutObject::AttributeTableSourceLayer, context, currentLayerIdentifier );
756 QgsVectorLayer *ddLayer = qobject_cast< QgsVectorLayer * >( QgsLayoutUtils::mapLayerFromString( layerIdentifier, mLayout->project() ) );
757 if ( ddLayer )
758 mDataDefinedVectorLayer = ddLayer;
759 }
760
762}
763
764QVariant QgsLayoutItemAttributeTable::replaceWrapChar( const QVariant &variant ) const
765{
766 //avoid converting variants to string if not required (try to maintain original type for sorting)
767 if ( mWrapString.isEmpty() || !variant.toString().contains( mWrapString ) )
768 return variant;
769
770 QString replaced = variant.toString();
771 replaced.replace( mWrapString, QLatin1String( "\n" ) );
772 return replaced;
773}
774
775#ifdef HAVE_SERVER_PYTHON_PLUGINS
776QgsLayoutTableColumns QgsLayoutItemAttributeTable::filteredColumns()
777{
778
779 QgsLayoutTableColumns allowedColumns { mColumns };
780
781 // Filter columns
782 if ( mLayout->renderContext().featureFilterProvider() )
783 {
784
786
787 if ( ! source )
788 {
789 return allowedColumns;
790 }
791
792 QHash<const QString, QSet<QString>> columnAttributesMap;
793 QSet<QString> allowedAttributes;
794
795 for ( const auto &c : std::as_const( allowedColumns ) )
796 {
797 if ( ! c.attribute().isEmpty() && ! columnAttributesMap.contains( c.attribute() ) )
798 {
799 columnAttributesMap[ c.attribute() ] = QSet<QString>();
800 const QgsExpression columnExp { c.attribute() };
801 const auto constRefs { columnExp.findNodes<QgsExpressionNodeColumnRef>() };
802 for ( const auto &cref : constRefs )
803 {
804 columnAttributesMap[ c.attribute() ].insert( cref->name() );
805 allowedAttributes.insert( cref->name() );
806 }
807 }
808 }
809
810 const QStringList filteredAttributes { layout()->renderContext().featureFilterProvider()->layerAttributes( source, allowedAttributes.values() ) };
811 const QSet<QString> filteredAttributesSet( filteredAttributes.constBegin(), filteredAttributes.constEnd() );
812 if ( filteredAttributesSet != allowedAttributes )
813 {
814 const auto forbidden { allowedAttributes.subtract( filteredAttributesSet ) };
815 allowedColumns.erase( std::remove_if( allowedColumns.begin(), allowedColumns.end(), [ &columnAttributesMap, &forbidden ]( QgsLayoutTableColumn & c ) -> bool
816 {
817 for ( const auto &f : std::as_const( forbidden ) )
818 {
819 if ( columnAttributesMap[ c.attribute() ].contains( f ) )
820 {
821 return true;
822 }
823 }
824 return false;
825 } ), allowedColumns.end() );
826
827 }
828 }
829
830 return allowedColumns;
831}
832#endif
833
835{
836 switch ( mSource )
837 {
839 return mLayout->reportContext().layer();
841 {
842 if ( mDataDefinedVectorLayer )
843 return mDataDefinedVectorLayer;
844 else
845 return mVectorLayer.get();
846 }
848 {
849 QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
850 return relation.referencingLayer();
851 }
852 }
853 return nullptr;
854}
855
856void QgsLayoutItemAttributeTable::removeLayer( const QString &layerId )
857{
858 if ( mVectorLayer && mSource == QgsLayoutItemAttributeTable::LayerAttributes )
859 {
860 if ( layerId == mVectorLayer->id() )
861 {
862 mVectorLayer.setLayer( nullptr );
863 //remove existing columns
864 mColumns.clear();
865 }
866 }
867}
868
869void QgsLayoutItemAttributeTable::setWrapString( const QString &wrapString )
870{
871 if ( wrapString == mWrapString )
872 {
873 return;
874 }
875
876 mWrapString = wrapString;
878 emit changed();
879}
880
881bool QgsLayoutItemAttributeTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
882{
883 if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
884 return false;
885
886 tableElem.setAttribute( QStringLiteral( "source" ), QString::number( static_cast< int >( mSource ) ) );
887 tableElem.setAttribute( QStringLiteral( "relationId" ), mRelationId );
888 tableElem.setAttribute( QStringLiteral( "showUniqueRowsOnly" ), mShowUniqueRowsOnly );
889 tableElem.setAttribute( QStringLiteral( "showOnlyVisibleFeatures" ), mShowOnlyVisibleFeatures );
890 tableElem.setAttribute( QStringLiteral( "filterToAtlasIntersection" ), mFilterToAtlasIntersection );
891 tableElem.setAttribute( QStringLiteral( "maxFeatures" ), mMaximumNumberOfFeatures );
892 tableElem.setAttribute( QStringLiteral( "filterFeatures" ), mFilterFeatures ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
893 tableElem.setAttribute( QStringLiteral( "featureFilter" ), mFeatureFilter );
894 tableElem.setAttribute( QStringLiteral( "wrapString" ), mWrapString );
895 tableElem.setAttribute( QStringLiteral( "useConditionalStyling" ), mUseConditionalStyling );
896
897 if ( mMap )
898 {
899 tableElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
900 }
901
902 if ( mVectorLayer )
903 {
904 tableElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer.layerId );
905 tableElem.setAttribute( QStringLiteral( "vectorLayerName" ), mVectorLayer.name );
906 tableElem.setAttribute( QStringLiteral( "vectorLayerSource" ), mVectorLayer.source );
907 tableElem.setAttribute( QStringLiteral( "vectorLayerProvider" ), mVectorLayer.provider );
908 }
909 return true;
910}
911
912bool QgsLayoutItemAttributeTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
913{
914 if ( QgsVectorLayer *prevLayer = sourceLayer() )
915 {
916 //disconnect from previous layer
918 }
919
920 if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
921 return false;
922
923 mSource = QgsLayoutItemAttributeTable::ContentSource( itemElem.attribute( QStringLiteral( "source" ), QStringLiteral( "0" ) ).toInt() );
924 mRelationId = itemElem.attribute( QStringLiteral( "relationId" ), QString() );
925
927 {
928 mCurrentAtlasLayer = mLayout->reportContext().layer();
929 }
930
931 mShowUniqueRowsOnly = itemElem.attribute( QStringLiteral( "showUniqueRowsOnly" ), QStringLiteral( "0" ) ).toInt();
932 mShowOnlyVisibleFeatures = itemElem.attribute( QStringLiteral( "showOnlyVisibleFeatures" ), QStringLiteral( "1" ) ).toInt();
933 mFilterToAtlasIntersection = itemElem.attribute( QStringLiteral( "filterToAtlasIntersection" ), QStringLiteral( "0" ) ).toInt();
934 mFilterFeatures = itemElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
935 mFeatureFilter = itemElem.attribute( QStringLiteral( "featureFilter" ), QString() );
936 mMaximumNumberOfFeatures = itemElem.attribute( QStringLiteral( "maxFeatures" ), QStringLiteral( "5" ) ).toInt();
937 mWrapString = itemElem.attribute( QStringLiteral( "wrapString" ) );
938 mUseConditionalStyling = itemElem.attribute( QStringLiteral( "useConditionalStyling" ), QStringLiteral( "0" ) ).toInt();
939
940 //map
941 mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
942 if ( mMap )
943 {
946 mMap = nullptr;
947 }
948 // setting new mMap occurs in finalizeRestoreFromXml
949
950 //vector layer
951 QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
952 QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
953 QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
954 QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
955 mVectorLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
956 mVectorLayer.resolveWeakly( mLayout->project() );
957
958 //connect to new layer
959 if ( QgsVectorLayer *newLayer = sourceLayer() )
961
963
964 emit changed();
965 return true;
966}
967
969{
970 if ( source == mSource )
971 {
972 return;
973 }
974
975 QgsVectorLayer *prevLayer = sourceLayer();
976 mSource = source;
977 QgsVectorLayer *newLayer = sourceLayer();
978
979 if ( newLayer != prevLayer )
980 {
981 //disconnect from previous layer
982 if ( prevLayer )
983 {
985 }
986
987 //connect to new layer
990 {
991 mCurrentAtlasLayer = newLayer;
992 }
993
994 //layer has changed as a result of the source change, so reset column list
995 resetColumns();
996 }
997
999 emit changed();
1000}
@ Reverse
Reverse/inverse transform (from destination to source)
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.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
The QgsConditionalLayerStyles class holds conditional style information for a layer.
QgsConditionalStyles rowStyles() const
Returns a list of row styles associated with the layer.
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName) const
Returns the conditional styles set for the field with matching fieldName.
Conditional styling for a rule.
static QgsConditionalStyle compressStyles(const QList< QgsConditionalStyle > &styles)
Compress a list of styles into a single style.
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
QFont font() const
The font for the style.
bool isValid() const
isValid Check if this rule is valid.
Class for doing transforms between two map coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
Holder for the widget type and its configuration for a field.
QVariantMap config() const
virtual QgsExpressionContext createExpressionContext() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
An expression node which takes it value from a feature's field.
Class for parsing and evaluation of expressions (formerly called "search strings").
QList< const T * > findNodes() const
Returns a list of all nodes of the given class which are used in this expression.
virtual QStringList layerAttributes(const QgsVectorLayer *layer, const QStringList &attributes) const =0
Returns the list of visible attribute names from a list of attributes names for the given layer.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & addOrderBy(const QString &expression, bool ascending=true)
Adds a new OrderByClause, appending it as the least important one.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets the feature ID that should be fetched.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:56
QgsAttributes attributes
Definition qgsfeature.h:65
QgsFeatureId id
Definition qgsfeature.h:64
QgsGeometry geometry
Definition qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
QgsFieldFormatter * fieldFormatter(const QString &id) const
Gets a field formatter by its id.
A field formatter helps to handle and display values for a field.
virtual QVariant createCache(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config) const
Create a cache for a given field.
virtual QString representValue(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value) const
Create a pretty String representation of the value.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:51
QString name
Definition qgsfield.h:60
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition qgsfield.cpp:672
Container of fields for a vector layer.
Definition qgsfields.h:45
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static QString resolveFontStyleName(const QFont &font)
Attempts to resolve the style name corresponding to the specified font object.
A geometry is the spatial representation of a feature.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
A layout table subclass that displays attributes from a vector layer.
void resetColumns()
Resets the attribute table's columns to match the vector layer's fields.
QString wrapString() const
Returns the string used to wrap the contents of the table cells by.
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
ContentSource
Specifies the content source for the attribute table.
@ AtlasFeature
Table shows attributes from the current atlas feature.
@ RelationChildren
Table shows attributes from related child features.
@ LayerAttributes
Table shows attributes from features in a vector layer.
QgsVectorLayer * sourceLayer() const
Returns the source layer for the table, considering the table source mode.
void setDisplayedFields(const QStringList &fields, bool refresh=true)
Sets the attributes to display in the table.
void setUseConditionalStyling(bool enabled)
Sets whether the attribute table will be rendered using the conditional styling properties of the lin...
void setRelationId(const QString &id)
Sets the relation id from which to display child features.
void setMaximumNumberOfFeatures(int features)
Sets the maximum number of features shown by the table.
void setDisplayOnlyVisibleFeatures(bool visibleOnly)
Sets the attribute table to only show features which are visible in a map item.
void setFeatureFilter(const QString &expression)
Sets the expression used for filtering features in the table.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
bool useConditionalStyling() const
Returns true if the attribute table will be rendered using the conditional styling properties of the ...
ContentSource source() const
Returns the source for attributes shown in the table body.
int type() const override
Returns unique multiframe type id.
QgsConditionalStyle conditionalCellStyle(int row, int column) const override
Returns the conditional style to use for the cell at row, column.
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties) override
Refreshes a data defined property for the multi frame by reevaluating the property's value and redraw...
QgsExpressionContextScope * scopeForCell(int row, int column) const override
Creates a new QgsExpressionContextScope for the cell at row, column.
void setFilterFeatures(bool filter)
Sets whether the feature filter is active for the attribute table.
QgsLayoutItemMap * map() const
Returns the layout map whose extents are controlling the features shown in the table.
void setUniqueRowsOnly(bool uniqueOnly)
Sets attribute table to only show unique rows.
QString relationId() const
Returns the relation id which the table displays child features from.
void setWrapString(const QString &wrapString)
Sets a string to wrap the contents of the table cells by.
QIcon icon() const override
Returns the item's icon.
void setMap(QgsLayoutItemMap *map)
Sets a layout map to use to limit the extent of features shown in the attribute table.
void setFilterToAtlasFeature(bool filterToAtlas)
Sets attribute table to only show features which intersect the current atlas feature.
QString displayName() const override
Returns the multiframe display name.
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
bool getTableContents(QgsLayoutTableContents &contents) override
Queries the attribute table's vector layer for attributes to show in the table.
QgsLayoutItemAttributeTable(QgsLayout *layout)
Constructor for QgsLayoutItemAttributeTable, attached to the specified layout.
QgsTextFormat textFormatForCell(int row, int column) const override
Returns the text format to use for the cell at the specified row and column.
static QgsLayoutItemAttributeTable * create(QgsLayout *layout)
Returns a new QgsLayoutItemAttributeTable for the specified parent layout.
void setVectorLayer(QgsVectorLayer *layer)
Sets the vector layer from which to display feature attributes.
void setSource(ContentSource source)
Sets the source for attributes to show in table body.
Layout graphical items for displaying a map.
void extentChanged()
Emitted when the map's extent changes.
void mapRotationChanged(double newRotation)
Emitted when the map's rotation changes.
@ LayoutAttributeTable
Attribute table.
virtual void finalizeRestoreFromXml()
Called after all pending items have been restored from XML.
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties)
Refreshes a data defined property for the multi frame by reevaluating the property's value and redraw...
QgsPropertyCollection mDataDefinedProperties
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
QPointer< QgsLayout > mLayout
DataDefinedProperty
Data defined properties for different item types.
@ AttributeTableSourceLayer
Attribute table source layer.
@ AllProperties
All properties for item.
QgsFeatureFilterProvider * featureFilterProvider() const
Returns the possibly NULL feature filter provider.
void layerChanged(QgsVectorLayer *layer)
Emitted when the context's layer is changed.
Stores properties of a column for a QgsLayoutTable.
void setAttribute(const QString &attribute)
Sets the attribute name or expression used for the column's values.
void setHeading(const QString &heading)
Sets the heading for a column, which is the value displayed in the column's header cell.
A class to display a table in the print layout, and allow the table to span over multiple frames.
virtual void refreshAttributes()
Refreshes the contents shown in the table by querying for new data.
void recalculateTableSize()
Recalculates and updates the size of the table and all table frames.
virtual QgsExpressionContextScope * scopeForCell(int row, int column) const
Creates a new QgsExpressionContextScope for the cell at row, column.
bool contentsContainsRow(const QgsLayoutTableContents &contents, const QgsLayoutTableRow &row) const
Checks whether a table contents contains a given row.
QgsLayoutTableColumns mColumns
Columns to show in table.
QgsTextFormat mContentTextFormat
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
QgsLayoutTableSortColumns mSortColumns
Columns to sort the table.
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
QgsLayoutTableContents & contents()
Returns the current contents of the table.
void refresh() override
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProject *project)
Resolves a string into a map layer from a given project.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition qgslayout.h:51
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout's render context, which stores information relating to the current ...
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:79
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
void layerModified()
Emitted when modifications has been done on layer.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:104
void layerWillBeRemoved(const QString &layerId)
Emitted when a layer is about to be removed from the registry.
The class is used as a container of context for various read/write operations on other objects.
A rectangle specified with double values.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
bool isEmpty() const
Returns true if the rectangle is empty.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
QgsVectorLayer * referencingLayer
Definition qgsrelation.h:46
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
Container for all settings relating to text rendering.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setForcedItalic(bool forced)
Sets whether the format is set to force an italic style.
void setForcedBold(bool forced)
Sets whether the format is set to force a bold style.
QFont font() const
Returns the font used for rendering text.
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
QVector< QgsLayoutTableColumn > QgsLayoutTableColumns
List of column definitions for a QgsLayoutTable.
QVector< QgsLayoutTableRow > QgsLayoutTableContents
List of QgsLayoutTableRows, representing rows and column cell contents for a QgsLayoutTable.
QVector< QVariant > QgsLayoutTableRow
List of QVariants, representing a the contents of a single row in a QgsLayoutTable.
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
const QgsField & field
Definition qgsfield.h:476
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
Single variable definition for use within a QgsExpressionContextScope.
TYPE * resolveWeakly(const QgsProject *project, MatchType matchType=MatchType::All)
Resolves the map layer by attempting to find a matching layer in a project using a weak match.
QString source
Weak reference to layer public source.
QString name
Weak reference to layer name.
TYPE * get() const
Returns a pointer to the layer, or nullptr if the reference has not yet been matched to a layer.
QString provider
Weak reference to layer provider.
void setLayer(TYPE *l)
Sets the reference to point to a specified layer.
QString layerId
Original layer ID.