QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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
20#include "qgsconditionalstyle.h"
21#include "qgsexception.h"
24#include "qgsfeatureiterator.h"
25#include "qgsfieldformatter.h"
27#include "qgsfontutils.h"
28#include "qgsgeometry.h"
29#include "qgsgeometryengine.h"
30#include "qgslayout.h"
31#include "qgslayoutframe.h"
32#include "qgslayoutitemmap.h"
36#include "qgslayoututils.h"
37#include "qgsproject.h"
38#include "qgsrelationmanager.h"
39#include "qgsvariantutils.h"
40#include "qgsvectorlayer.h"
41
42#include "moc_qgslayoutitemattributetable.cpp"
43
44//
45// QgsLayoutItemAttributeTable
46//
47
50{
51 if ( mLayout )
52 {
53 connect( mLayout->project(), static_cast < void ( QgsProject::* )( const QString & ) >( &QgsProject::layerWillBeRemoved ), this, &QgsLayoutItemAttributeTable::removeLayer );
54
55 //coverage layer change = regenerate columns
56 connect( &mLayout->reportContext(), &QgsLayoutReportContext::layerChanged, this, &QgsLayoutItemAttributeTable::atlasLayerChanged );
57 }
59}
60
65
67{
68 return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemTable.svg" ) );
69}
70
75
77{
78 return tr( "<Attribute table frame>" );
79}
80
82{
83 if ( layer == mVectorLayer.get() )
84 {
85 //no change
86 return;
87 }
88
89 QgsVectorLayer *prevLayer = sourceLayer();
90 mVectorLayer.setLayer( layer );
91
92 if ( mSource == QgsLayoutItemAttributeTable::LayerAttributes && layer != prevLayer )
93 {
94 if ( prevLayer )
95 {
96 //disconnect from previous layer
98 }
99
100 //rebuild column list to match all columns from layer
101 resetColumns();
102
103 //listen for modifications to layer and refresh table when they occur
104 connect( mVectorLayer.get(), &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
105 }
106
108 emit changed();
109}
110
112{
113 if ( relationId == mRelationId )
114 {
115 //no change
116 return;
117 }
118
119 QgsVectorLayer *prevLayer = sourceLayer();
120 mRelationId = relationId;
121 QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
122 QgsVectorLayer *newLayer = relation.referencingLayer();
123
124 if ( mSource == QgsLayoutItemAttributeTable::RelationChildren && newLayer != prevLayer )
125 {
126 if ( prevLayer )
127 {
128 //disconnect from previous layer
130 }
131
132 //rebuild column list to match all columns from layer
133 resetColumns();
134
135 //listen for modifications to layer and refresh table when they occur
137 }
138
140 emit changed();
141}
142
143void QgsLayoutItemAttributeTable::atlasLayerChanged( QgsVectorLayer *layer )
144{
145 if ( mSource != QgsLayoutItemAttributeTable::AtlasFeature || layer == mCurrentAtlasLayer )
146 {
147 //nothing to do
148 return;
149 }
150
151 //atlas feature mode, atlas layer changed, so we need to reset columns
152 if ( mCurrentAtlasLayer )
153 {
154 //disconnect from previous layer
155 disconnect( mCurrentAtlasLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
156 }
157
158 const bool mustRebuildColumns = static_cast< bool >( mCurrentAtlasLayer ) || mColumns.empty();
159 mCurrentAtlasLayer = layer;
160
161 if ( mustRebuildColumns )
162 {
163 //rebuild column list to match all columns from layer
164 resetColumns();
165 }
166
168
169 //listen for modifications to layer and refresh table when they occur
171}
172
174{
176 if ( !source )
177 {
178 return;
179 }
180
181 //remove existing columns
182 mColumns.clear();
183 mSortColumns.clear();
184
185 //rebuild columns list from vector layer fields
186 int idx = 0;
187 const QgsFields sourceFields = source->fields();
188
189 for ( const auto &field : sourceFields )
190 {
191 QString currentAlias = source->attributeDisplayName( idx );
193 col.setAttribute( field.name() );
194 col.setHeading( currentAlias );
195 mColumns.append( col );
196 idx++;
197 }
198}
199
200void QgsLayoutItemAttributeTable::disconnectCurrentMap()
201{
202 if ( !mMap )
203 {
204 return;
205 }
206
209 disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemAttributeTable::disconnectCurrentMap );
210 mMap = nullptr;
211}
212
214{
215 return mUseConditionalStyling;
216}
217
219{
220 if ( useConditionalStyling == mUseConditionalStyling )
221 {
222 return;
223 }
224
225 mUseConditionalStyling = useConditionalStyling;
227 emit changed();
228}
229
231{
232 if ( map == mMap )
233 {
234 //no change
235 return;
236 }
237 disconnectCurrentMap();
238
239 mMap = map;
240 if ( mMap )
241 {
242 //listen out for extent changes in linked map
245 }
247 emit changed();
248}
249
251{
252 if ( features == mMaximumNumberOfFeatures )
253 {
254 return;
255 }
256
257 mMaximumNumberOfFeatures = features;
259 emit changed();
260}
261
263{
264 if ( uniqueOnly == mShowUniqueRowsOnly )
265 {
266 return;
267 }
268
269 mShowUniqueRowsOnly = uniqueOnly;
271 emit changed();
272}
273
275{
276 if ( visibleOnly == mShowOnlyVisibleFeatures )
277 {
278 return;
279 }
280
281 mShowOnlyVisibleFeatures = visibleOnly;
283 emit changed();
284}
285
287{
288 if ( filterToAtlas == mFilterToAtlasIntersection )
289 {
290 return;
291 }
292
293 mFilterToAtlasIntersection = filterToAtlas;
295 emit changed();
296}
297
299{
300 if ( filter == mFilterFeatures )
301 {
302 return;
303 }
304
305 mFilterFeatures = filter;
307 emit changed();
308}
309
310void QgsLayoutItemAttributeTable::setFeatureFilter( const QString &expression )
311{
312 if ( expression == mFeatureFilter )
313 {
314 return;
315 }
316
317 mFeatureFilter = expression;
319 emit changed();
320}
321
322void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields, bool refresh )
323{
325 if ( !source )
326 {
327 return;
328 }
329
330 //rebuild columns list, taking only fields contained in supplied list
331 mColumns.clear();
332
333 const QgsFields layerFields = source->fields();
334
335 if ( !fields.isEmpty() )
336 {
337 for ( const QString &field : fields )
338 {
339 int attrIdx = layerFields.lookupField( field );
340 if ( attrIdx < 0 )
341 {
342 continue;
343 }
344 QString currentAlias = source->attributeDisplayName( attrIdx );
346 col.setAttribute( layerFields.at( attrIdx ).name() );
347 col.setHeading( currentAlias );
348 mColumns.append( col );
349 }
350 }
351 else
352 {
353 //resetting, so add all attributes to columns
354 int idx = 0;
355 for ( const QgsField &field : layerFields )
356 {
357 QString currentAlias = source->attributeDisplayName( idx );
359 col.setAttribute( field.name() );
360 col.setHeading( currentAlias );
361 mColumns.append( col );
362 idx++;
363 }
364 }
365
366 if ( refresh )
367 {
369 }
370}
371
372void QgsLayoutItemAttributeTable::restoreFieldAliasMap( const QMap<int, QString> &map )
373{
375 if ( !source )
376 {
377 return;
378 }
379
380 for ( int i = 0; i < mColumns.count(); i++ )
381 {
382 int attrIdx = source->fields().lookupField( mColumns[i].attribute() );
383 if ( map.contains( attrIdx ) )
384 {
385 mColumns[i].setHeading( map.value( attrIdx ) );
386 }
387 else
388 {
389 mColumns[i].setHeading( source->attributeDisplayName( attrIdx ) );
390 }
391 }
392}
393
395{
396 contents.clear();
397 mLayerCache.clear();
398
399 QgsVectorLayer *layer = sourceLayer();
400 if ( !layer )
401 {
402 //no source layer
403 return false;
404 }
405
406 const QgsConditionalLayerStyles *conditionalStyles = layer->conditionalStyles();
407
409 context.setFields( layer->fields() );
410
412 req.setExpressionContext( context );
413
414 //prepare filter expression
415 std::unique_ptr<QgsExpression> filterExpression;
416 bool activeFilter = false;
417 if ( mFilterFeatures && !mFeatureFilter.isEmpty() )
418 {
419 filterExpression = std::make_unique< QgsExpression >( mFeatureFilter );
420 if ( !filterExpression->hasParserError() )
421 {
422 activeFilter = true;
423 req.setFilterExpression( mFeatureFilter );
424 }
425 }
426
427#ifdef HAVE_SERVER_PYTHON_PLUGINS
428 if ( mLayout->renderContext().featureFilterProvider() )
429 {
430 // NOLINTBEGIN(bugprone-branch-clone)
432 if ( mLayout->renderContext().featureFilterProvider()->isFilterThreadSafe() )
433 {
434 mLayout->renderContext().featureFilterProvider()->filterFeatures( layer->id(), req );
435 }
436 else
437 {
438 mLayout->renderContext().featureFilterProvider()->filterFeatures( layer, req );
439 }
441 // NOLINTEND(bugprone-branch-clone)
442 }
443#endif
444
445 QgsRectangle selectionRect;
446 QgsGeometry visibleRegion;
447 std::unique_ptr< QgsGeometryEngine > visibleMapEngine;
448 if ( mMap && mShowOnlyVisibleFeatures )
449 {
450 visibleRegion = QgsGeometry::fromQPolygonF( mMap->visibleExtentPolygon() );
451 selectionRect = visibleRegion.boundingBox();
452 //transform back to layer CRS
453 const QgsCoordinateTransform coordTransform( layer->crs(), mMap->crs(), mLayout->project() );
454 QgsCoordinateTransform extentTransform = coordTransform;
455 extentTransform.setBallparkTransformsAreAppropriate( true );
456 try
457 {
458 selectionRect = extentTransform.transformBoundingBox( selectionRect, Qgis::TransformDirection::Reverse );
459 visibleRegion.transform( coordTransform, Qgis::TransformDirection::Reverse );
460 }
461 catch ( QgsCsException &cse )
462 {
463 Q_UNUSED( cse )
464 return false;
465 }
466 visibleMapEngine.reset( QgsGeometry::createGeometryEngine( visibleRegion.constGet() ) );
467 visibleMapEngine->prepareGeometry();
468 }
469
470 QgsGeometry atlasGeometry;
471 std::unique_ptr< QgsGeometryEngine > atlasGeometryEngine;
472 if ( mFilterToAtlasIntersection )
473 {
474 atlasGeometry = mLayout->reportContext().currentGeometry( layer->crs() );
475 if ( !atlasGeometry.isNull() )
476 {
477 if ( selectionRect.isNull() )
478 {
479 selectionRect = atlasGeometry.boundingBox();
480 }
481 else
482 {
483 selectionRect = selectionRect.intersect( atlasGeometry.boundingBox() );
484 }
485
486 atlasGeometryEngine.reset( QgsGeometry::createGeometryEngine( atlasGeometry.constGet() ) );
487 atlasGeometryEngine->prepareGeometry();
488 }
489 else
490 {
491 return false;
492 }
493 }
494
496 {
497 QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
498 QgsFeature atlasFeature = mLayout->reportContext().feature();
499 req = relation.getRelatedFeaturesRequest( atlasFeature );
500 }
501
502 if ( !selectionRect.isNull() )
503 req.setFilterRect( selectionRect );
504
506
508 {
509 //source mode is current atlas feature
510 QgsFeature atlasFeature = mLayout->reportContext().feature();
511 req.setFilterFid( atlasFeature.id() );
512 }
513
514 for ( const QgsLayoutTableColumn &column : std::as_const( mSortColumns ) )
515 {
516 req.addOrderBy( column.attribute(), column.sortOrder() == Qt::AscendingOrder );
517 }
518
519 QgsFeature f;
520 int counter = 0;
521 QgsFeatureIterator fit = layer->getFeatures( req );
522
523 mConditionalStyles.clear();
524 mFeatures.clear();
525
526 QVector< QVector< Cell > > tempContents;
527 QgsLayoutTableContents existingContents;
528
529 while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
530 {
531 context.setFeature( f );
532 //check feature against filter
533 if ( activeFilter && filterExpression )
534 {
535 QVariant result = filterExpression->evaluate( &context );
536 // skip this feature if the filter evaluation is false
537 if ( !result.toBool() )
538 {
539 continue;
540 }
541 }
542
543 // check against exact map bounds
544 if ( visibleMapEngine )
545 {
546 if ( !f.hasGeometry() )
547 continue;
548
549 if ( !visibleMapEngine->intersects( f.geometry().constGet() ) )
550 continue;
551 }
552
553 //check against atlas feature intersection
554 if ( atlasGeometryEngine )
555 {
556 if ( !f.hasGeometry() )
557 {
558 continue;
559 }
560
561 if ( !atlasGeometryEngine->intersects( f.geometry().constGet() ) )
562 continue;
563 }
564
565 QgsConditionalStyle rowStyle;
566
567 if ( mUseConditionalStyling )
568 {
569 const QList<QgsConditionalStyle> styles = QgsConditionalStyle::matchingConditionalStyles( conditionalStyles->rowStyles(), QVariant(), context );
570 rowStyle = QgsConditionalStyle::compressStyles( styles );
571 }
572
573 // We need to build up two different lists here -- one is a pair of the cell contents along with the cell style.
574 // 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
575 // correctly when this occurs
576 // We also need a list of just the cell contents, so that we can do a quick check for row uniqueness (when the
577 // corresponding option is enabled)
578 QVector< Cell > currentRow;
579#ifdef HAVE_SERVER_PYTHON_PLUGINS
580 mColumns = filteredColumns();
581#endif
582 currentRow.reserve( mColumns.count() );
583 QgsLayoutTableRow rowContents;
584 rowContents.reserve( mColumns.count() );
585
586 for ( const QgsLayoutTableColumn &column : std::as_const( mColumns ) )
587 {
589 int idx = layer->fields().lookupField( column.attribute() );
590 if ( idx != -1 )
591 {
592 QVariant val = f.attributes().at( idx );
593
594 if ( mUseConditionalStyling )
595 {
596 QList<QgsConditionalStyle> styles = conditionalStyles->fieldStyles( layer->fields().at( idx ).name() );
597 styles = QgsConditionalStyle::matchingConditionalStyles( styles, val, context );
598 styles.insert( 0, rowStyle );
599 style = QgsConditionalStyle::compressStyles( styles );
600 }
601
602 const QgsEditorWidgetSetup setup = layer->fields().at( idx ).editorWidgetSetup();
603
604 if ( ! setup.isNull() )
605 {
607 QVariant cache;
608
609 auto it = mLayerCache.constFind( column.attribute() );
610 if ( it != mLayerCache.constEnd() )
611 {
612 cache = it.value();
613 }
614 else
615 {
616 cache = fieldFormatter->createCache( layer, idx, setup.config() );
617 mLayerCache.insert( column.attribute(), cache );
618 }
619
620 val = fieldFormatter->representValue( layer, idx, setup.config(), cache, val );
621 }
622
623 QVariant v = QgsVariantUtils::isNull( val ) ? QString() : replaceWrapChar( val );
624 currentRow << Cell( v, style, f );
625 rowContents << v;
626 }
627 else
628 {
629 // Lets assume it's an expression
630 auto expression = std::make_unique< QgsExpression >( column.attribute() );
631 context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "row_number" ), counter + 1, true ) );
632 expression->prepare( &context );
633 QVariant value = expression->evaluate( &context );
634
635 currentRow << Cell( value, rowStyle, f );
636 rowContents << value;
637 }
638 }
639
640 if ( mShowUniqueRowsOnly )
641 {
642 if ( contentsContainsRow( existingContents, rowContents ) )
643 continue;
644 }
645
646 tempContents << currentRow;
647 existingContents << rowContents;
648 ++counter;
649 }
650
651 // build final table contents
652 contents.reserve( tempContents.size() );
653 mConditionalStyles.reserve( tempContents.size() );
654 mFeatures.reserve( tempContents.size() );
655 for ( auto it = tempContents.constBegin(); it != tempContents.constEnd(); ++it )
656 {
658 QList< QgsConditionalStyle > rowStyles;
659 row.reserve( it->size() );
660 rowStyles.reserve( it->size() );
661
662 for ( auto cellIt = it->constBegin(); cellIt != it->constEnd(); ++cellIt )
663 {
664 row << cellIt->content;
665 rowStyles << cellIt->style;
666 if ( cellIt == it->constBegin() )
667 mFeatures << cellIt->feature;
668 }
669 contents << row;
670 mConditionalStyles << rowStyles;
671 }
672
674 return true;
675}
676
678{
679 if ( row >= mConditionalStyles.size() )
680 return QgsConditionalStyle();
681
682 return mConditionalStyles.at( row ).at( column );
683}
684
686{
688
689 const QgsConditionalStyle style = conditionalCellStyle( row, column );
690 if ( style.isValid() )
691 {
692 // apply conditional style formatting to text format
693 const QFont styleFont = style.font();
694 if ( styleFont != QFont() )
695 {
696 QFont newFont = format.font();
697 // we want to keep all the other font settings, like word/letter spacing
698 QgsFontUtils::setFontFamily( newFont, styleFont.family() );
699
700 // warning -- there's a potential trap here! We can't just read QFont::styleName(), as that may be blank even when
701 // the font has the bold or italic attributes set! Reading the style name via QFontInfo avoids this and always returns
702 // a correct style name
703 const QString styleName = QgsFontUtils::resolveFontStyleName( styleFont );
704 if ( !styleName.isEmpty() )
705 newFont.setStyleName( styleName );
706
707 newFont.setStrikeOut( styleFont.strikeOut() );
708 newFont.setUnderline( styleFont.underline() );
709 format.setFont( newFont );
710 if ( styleName.isEmpty() )
711 {
712 // we couldn't find a direct match for the conditional font's bold/italic settings as a font style name.
713 // This means the conditional style is using Qt's "faux bold/italic" mode. Even though it causes reduced quality font
714 // rendering, we'll apply it here anyway just to ensure that the rendered font styling matches the conditional style.
715 if ( styleFont.bold() )
716 format.setForcedBold( true );
717 if ( styleFont.italic() )
718 format.setForcedItalic( true );
719 }
720 }
721 }
722
723 return format;
724}
725
727{
728 std::unique_ptr< QgsExpressionContextScope >scope( QgsLayoutTable::scopeForCell( row, column ) );
729 scope->setFeature( mFeatures.value( row ) );
730 scope->setFields( scope->feature().fields() );
731 return scope.release();
732}
733
735{
737
738 if ( mSource == LayerAttributes )
739 {
740 context.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer.get() ) );
741 }
742
743 return context;
744}
745
747{
749 if ( !mMap && !mMapUuid.isEmpty() && mLayout )
750 {
751 mMap = qobject_cast< QgsLayoutItemMap *>( mLayout->itemByUuid( mMapUuid, true ) );
752 if ( mMap )
753 {
754 //if we have found a valid map item, listen out to extent changes on it and refresh the table
757 }
758 }
759}
760
762{
764
767 {
768 mDataDefinedVectorLayer = nullptr;
769
770 QString currentLayerIdentifier;
771 if ( QgsVectorLayer *currentLayer = mVectorLayer.get() )
772 currentLayerIdentifier = currentLayer->id();
773
774 const QString layerIdentifier = mDataDefinedProperties.valueAsString( QgsLayoutObject::DataDefinedProperty::AttributeTableSourceLayer, context, currentLayerIdentifier );
775 QgsVectorLayer *ddLayer = qobject_cast< QgsVectorLayer * >( QgsLayoutUtils::mapLayerFromString( layerIdentifier, mLayout->project() ) );
776 if ( ddLayer )
777 mDataDefinedVectorLayer = ddLayer;
778 }
779
781}
782
783QVariant QgsLayoutItemAttributeTable::replaceWrapChar( const QVariant &variant ) const
784{
785 //avoid converting variants to string if not required (try to maintain original type for sorting)
786 if ( mWrapString.isEmpty() || !variant.toString().contains( mWrapString ) )
787 return variant;
788
789 QString replaced = variant.toString();
790 replaced.replace( mWrapString, QLatin1String( "\n" ) );
791 return replaced;
792}
793
794#ifdef HAVE_SERVER_PYTHON_PLUGINS
795QgsLayoutTableColumns QgsLayoutItemAttributeTable::filteredColumns()
796{
797
798 QgsLayoutTableColumns allowedColumns { mColumns };
799
800 // Filter columns
801 if ( mLayout->renderContext().featureFilterProvider() )
802 {
803
804 QgsVectorLayer *source { sourceLayer() };
805
806 if ( ! source )
807 {
808 return allowedColumns;
809 }
810
811 QHash<const QString, QSet<QString>> columnAttributesMap;
812 QSet<QString> allowedAttributes;
813
814 for ( const auto &c : std::as_const( allowedColumns ) )
815 {
816 if ( ! c.attribute().isEmpty() && ! columnAttributesMap.contains( c.attribute() ) )
817 {
818 columnAttributesMap[ c.attribute() ] = QSet<QString>();
819 const QgsExpression columnExp { c.attribute() };
820 const auto constRefs { columnExp.findNodes<QgsExpressionNodeColumnRef>() };
821 for ( const auto &cref : constRefs )
822 {
823 columnAttributesMap[ c.attribute() ].insert( cref->name() );
824 allowedAttributes.insert( cref->name() );
825 }
826 }
827 }
828
829 const QStringList filteredAttributes { layout()->renderContext().featureFilterProvider()->layerAttributes( source, allowedAttributes.values() ) };
830 const QSet<QString> filteredAttributesSet( filteredAttributes.constBegin(), filteredAttributes.constEnd() );
831 if ( filteredAttributesSet != allowedAttributes )
832 {
833 const auto forbidden { allowedAttributes.subtract( filteredAttributesSet ) };
834 allowedColumns.erase( std::remove_if( allowedColumns.begin(), allowedColumns.end(), [ &columnAttributesMap, &forbidden ]( QgsLayoutTableColumn & c ) -> bool
835 {
836 for ( const auto &f : std::as_const( forbidden ) )
837 {
838 if ( columnAttributesMap[ c.attribute() ].contains( f ) )
839 {
840 return true;
841 }
842 }
843 return false;
844 } ), allowedColumns.end() );
845
846 }
847 }
848
849 return allowedColumns;
850}
851#endif
852
854{
855 switch ( mSource )
856 {
858 return mLayout->reportContext().layer();
860 {
861 if ( mDataDefinedVectorLayer )
862 return mDataDefinedVectorLayer;
863 else
864 return mVectorLayer.get();
865 }
867 {
868 QgsRelation relation = mLayout->project()->relationManager()->relation( mRelationId );
869 return relation.referencingLayer();
870 }
871 }
872 return nullptr;
873}
874
875void QgsLayoutItemAttributeTable::removeLayer( const QString &layerId )
876{
877 if ( mVectorLayer && mSource == QgsLayoutItemAttributeTable::LayerAttributes )
878 {
879 if ( layerId == mVectorLayer->id() )
880 {
881 mVectorLayer.setLayer( nullptr );
882 //remove existing columns
883 mColumns.clear();
884 }
885 }
886}
887
889{
890 if ( wrapString == mWrapString )
891 {
892 return;
893 }
894
895 mWrapString = wrapString;
897 emit changed();
898}
899
900bool QgsLayoutItemAttributeTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
901{
902 if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
903 return false;
904
905 tableElem.setAttribute( QStringLiteral( "source" ), QString::number( static_cast< int >( mSource ) ) );
906 tableElem.setAttribute( QStringLiteral( "relationId" ), mRelationId );
907 tableElem.setAttribute( QStringLiteral( "showUniqueRowsOnly" ), mShowUniqueRowsOnly );
908 tableElem.setAttribute( QStringLiteral( "showOnlyVisibleFeatures" ), mShowOnlyVisibleFeatures );
909 tableElem.setAttribute( QStringLiteral( "filterToAtlasIntersection" ), mFilterToAtlasIntersection );
910 tableElem.setAttribute( QStringLiteral( "maxFeatures" ), mMaximumNumberOfFeatures );
911 tableElem.setAttribute( QStringLiteral( "filterFeatures" ), mFilterFeatures ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
912 tableElem.setAttribute( QStringLiteral( "featureFilter" ), mFeatureFilter );
913 tableElem.setAttribute( QStringLiteral( "wrapString" ), mWrapString );
914 tableElem.setAttribute( QStringLiteral( "useConditionalStyling" ), mUseConditionalStyling );
915
916 if ( mMap )
917 {
918 tableElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
919 }
920
921 if ( mVectorLayer )
922 {
923 tableElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer.layerId );
924 tableElem.setAttribute( QStringLiteral( "vectorLayerName" ), mVectorLayer.name );
925 tableElem.setAttribute( QStringLiteral( "vectorLayerSource" ), mVectorLayer.source );
926 tableElem.setAttribute( QStringLiteral( "vectorLayerProvider" ), mVectorLayer.provider );
927 }
928 return true;
929}
930
931bool QgsLayoutItemAttributeTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
932{
933 if ( QgsVectorLayer *prevLayer = sourceLayer() )
934 {
935 //disconnect from previous layer
937 }
938
939 if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
940 return false;
941
942 mSource = QgsLayoutItemAttributeTable::ContentSource( itemElem.attribute( QStringLiteral( "source" ), QStringLiteral( "0" ) ).toInt() );
943 mRelationId = itemElem.attribute( QStringLiteral( "relationId" ), QString() );
944
946 {
947 mCurrentAtlasLayer = mLayout->reportContext().layer();
948 }
949
950 mShowUniqueRowsOnly = itemElem.attribute( QStringLiteral( "showUniqueRowsOnly" ), QStringLiteral( "0" ) ).toInt();
951 mShowOnlyVisibleFeatures = itemElem.attribute( QStringLiteral( "showOnlyVisibleFeatures" ), QStringLiteral( "1" ) ).toInt();
952 mFilterToAtlasIntersection = itemElem.attribute( QStringLiteral( "filterToAtlasIntersection" ), QStringLiteral( "0" ) ).toInt();
953 mFilterFeatures = itemElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
954 mFeatureFilter = itemElem.attribute( QStringLiteral( "featureFilter" ), QString() );
955 mMaximumNumberOfFeatures = itemElem.attribute( QStringLiteral( "maxFeatures" ), QStringLiteral( "5" ) ).toInt();
956 mWrapString = itemElem.attribute( QStringLiteral( "wrapString" ) );
957 mUseConditionalStyling = itemElem.attribute( QStringLiteral( "useConditionalStyling" ), QStringLiteral( "0" ) ).toInt();
958
959 //map
960 mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
961 if ( mMap )
962 {
965 mMap = nullptr;
966 }
967 // setting new mMap occurs in finalizeRestoreFromXml
968
969 //vector layer
970 QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
971 QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
972 QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
973 QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
974 mVectorLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
975 mVectorLayer.resolveWeakly( mLayout->project() );
976
977 //connect to new layer
978 if ( QgsVectorLayer *newLayer = sourceLayer() )
980
982
983 emit changed();
984 return true;
985}
986
988{
989 if ( source == mSource )
990 {
991 return;
992 }
993
994 QgsVectorLayer *prevLayer = sourceLayer();
995 mSource = source;
996 QgsVectorLayer *newLayer = sourceLayer();
997
998 if ( newLayer != prevLayer )
999 {
1000 //disconnect from previous layer
1001 if ( prevLayer )
1002 {
1003 disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
1004 }
1005
1006 //connect to new layer
1009 {
1010 mCurrentAtlasLayer = newLayer;
1011 }
1012
1013 //layer has changed as a result of the source change, so reset column list
1014 resetColumns();
1015 }
1016
1018 emit changed();
1019}
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
Definition qgis.h:2198
@ NoFlags
No flags are set.
Definition qgis.h:2195
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2673
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.
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.
Handles coordinate transforms between two 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.
QString type() const
Returns the widget type to use.
QVariantMap config() const
Returns the widget configuration.
bool isNull() const
Returns true if there is no widget configured.
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.
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)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags 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.
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:58
QgsAttributes attributes
Definition qgsfeature.h:67
QgsFeatureId id
Definition qgsfeature.h:66
QgsGeometry geometry
Definition qgsfeature.h:69
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:54
QString name
Definition qgsfield.h:63
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition qgsfield.cpp:747
Container of fields for a vector layer.
Definition qgsfields.h:46
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE 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.
static void setFontFamily(QFont &font, const QString &family)
Sets the family for a 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.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
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.
QgsExpressionContextScope * scopeForCell(int row, int column) const override
Creates a new QgsExpressionContextScope for the cell at row, column.
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::DataDefinedProperty::AllProperties) override
Refreshes a data defined property for the multi frame by reevaluating the property's value and redraw...
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::DataDefinedProperty::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 nullptr) 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.
QgsLayoutTable(QgsLayout *layout)
Constructor for QgsLayoutTable, belonging to the specified layout.
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.
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout's render context, which stores information relating to the current ...
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:87
QString id
Definition qgsmaplayer.h:83
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:109
void layerWillBeRemoved(const QString &layerId)
Emitted when a layer is about to be removed from the registry.
A container for the context for various read/write operations on objects.
A rectangle specified with double values.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Represents a relationship between two vector layers.
Definition qgsrelation.h:42
QgsVectorLayer * referencingLayer
Definition qgsrelation.h:47
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, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based dataset.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
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
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:7170
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7169
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
Single variable definition for use within a QgsExpressionContextScope.
void setLayer(TYPE *l)
Sets the reference to point to a specified layer.