1 /***************************************************************************
2                          qgslayoutattributetablewidget.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 
18 #include "qgslayoutattributetablewidget.h"
19 #include "qgslayoutatlas.h"
20 #include "qgslayout.h"
21 #include "qgslayoutframe.h"
22 #include "qgslayoutattributeselectiondialog.h"
23 #include "qgslayoutitemwidget.h"
24 #include "qgslayoutitemattributetable.h"
25 #include "qgslayouttablecolumn.h"
26 #include "qgslayoutitemmap.h"
27 #include "qgsvectorlayer.h"
28 #include "qgsexpressionbuilderdialog.h"
29 #include "qgsproject.h"
30 #include "qgsrelationmanager.h"
31 #include "qgsguiutils.h"
32 #include "qgslayouttablebackgroundcolorsdialog.h"
33 
QgsLayoutAttributeTableWidget(QgsLayoutFrame * frame)34 QgsLayoutAttributeTableWidget::QgsLayoutAttributeTableWidget( QgsLayoutFrame *frame )
35   : QgsLayoutItemBaseWidget( nullptr, frame ? qobject_cast< QgsLayoutItemAttributeTable* >( frame->multiFrame() ) : nullptr )
36   , mTable( frame ? qobject_cast< QgsLayoutItemAttributeTable* >( frame->multiFrame() ) : nullptr )
37   , mFrame( frame )
38 {
39   setupUi( this );
40   connect( mRefreshPushButton, &QPushButton::clicked, this, &QgsLayoutAttributeTableWidget::mRefreshPushButton_clicked );
41   connect( mAttributesPushButton, &QPushButton::clicked, this, &QgsLayoutAttributeTableWidget::mAttributesPushButton_clicked );
42   connect( mMaximumRowsSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutAttributeTableWidget::mMaximumRowsSpinBox_valueChanged );
43   connect( mMarginSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutAttributeTableWidget::mMarginSpinBox_valueChanged );
44   connect( mGridStrokeWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutAttributeTableWidget::mGridStrokeWidthSpinBox_valueChanged );
45   connect( mGridColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutAttributeTableWidget::mGridColorButton_colorChanged );
46   connect( mBackgroundColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutAttributeTableWidget::mBackgroundColorButton_colorChanged );
47   connect( mDrawHorizontalGrid, &QCheckBox::toggled, this, &QgsLayoutAttributeTableWidget::mDrawHorizontalGrid_toggled );
48   connect( mDrawVerticalGrid, &QCheckBox::toggled, this, &QgsLayoutAttributeTableWidget::mDrawVerticalGrid_toggled );
49   connect( mShowGridGroupCheckBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutAttributeTableWidget::mShowGridGroupCheckBox_toggled );
50   connect( mShowOnlyVisibleFeaturesCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutAttributeTableWidget::mShowOnlyVisibleFeaturesCheckBox_stateChanged );
51   connect( mFeatureFilterCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutAttributeTableWidget::mFeatureFilterCheckBox_stateChanged );
52   connect( mFeatureFilterEdit, &QLineEdit::editingFinished, this, &QgsLayoutAttributeTableWidget::mFeatureFilterEdit_editingFinished );
53   connect( mFeatureFilterButton, &QToolButton::clicked, this, &QgsLayoutAttributeTableWidget::mFeatureFilterButton_clicked );
54   connect( mHeaderHAlignmentComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutAttributeTableWidget::mHeaderHAlignmentComboBox_currentIndexChanged );
55   connect( mHeaderModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutAttributeTableWidget::mHeaderModeComboBox_currentIndexChanged );
56   connect( mWrapStringLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutAttributeTableWidget::mWrapStringLineEdit_editingFinished );
57   connect( mAddFramePushButton, &QPushButton::clicked, this, &QgsLayoutAttributeTableWidget::mAddFramePushButton_clicked );
58   connect( mResizeModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutAttributeTableWidget::mResizeModeComboBox_currentIndexChanged );
59   connect( mSourceComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutAttributeTableWidget::mSourceComboBox_currentIndexChanged );
60   connect( mRelationsComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutAttributeTableWidget::mRelationsComboBox_currentIndexChanged );
61   connect( mEmptyModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutAttributeTableWidget::mEmptyModeComboBox_currentIndexChanged );
62   connect( mDrawEmptyCheckBox, &QCheckBox::toggled, this, &QgsLayoutAttributeTableWidget::mDrawEmptyCheckBox_toggled );
63   connect( mEmptyMessageLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutAttributeTableWidget::mEmptyMessageLineEdit_editingFinished );
64   connect( mIntersectAtlasCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutAttributeTableWidget::mIntersectAtlasCheckBox_stateChanged );
65   connect( mUniqueOnlyCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutAttributeTableWidget::mUniqueOnlyCheckBox_stateChanged );
66   connect( mEmptyFrameCheckBox, &QCheckBox::toggled, this, &QgsLayoutAttributeTableWidget::mEmptyFrameCheckBox_toggled );
67   connect( mHideEmptyBgCheckBox, &QCheckBox::toggled, this, &QgsLayoutAttributeTableWidget::mHideEmptyBgCheckBox_toggled );
68   connect( mWrapBehaviorComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutAttributeTableWidget::mWrapBehaviorComboBox_currentIndexChanged );
69   connect( mAdvancedCustomizationButton, &QPushButton::clicked, this, &QgsLayoutAttributeTableWidget::mAdvancedCustomizationButton_clicked );
70   connect( mUseConditionalStylingCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutAttributeTableWidget::useConditionalStylingChanged );
71   setPanelTitle( tr( "Table Properties" ) );
72 
73   mContentFontToolButton->setMode( QgsFontButton::ModeTextRenderer );
74   mHeaderFontToolButton->setMode( QgsFontButton::ModeTextRenderer );
75 
76   mContentFontToolButton->registerExpressionContextGenerator( this );
77   mContentFontToolButton->setLayer( mTable->sourceLayer() );
78   mHeaderFontToolButton->registerExpressionContextGenerator( this );
79   mHeaderFontToolButton->setLayer( mTable->sourceLayer() );
80 
81   blockAllSignals( true );
82 
83   mResizeModeComboBox->addItem( tr( "Use Existing Frames" ), QgsLayoutMultiFrame::UseExistingFrames );
84   mResizeModeComboBox->addItem( tr( "Extend to Next Page" ), QgsLayoutMultiFrame::ExtendToNextPage );
85   mResizeModeComboBox->addItem( tr( "Repeat Until Finished" ), QgsLayoutMultiFrame::RepeatUntilFinished );
86 
87   mEmptyModeComboBox->addItem( tr( "Draw Headers Only" ), QgsLayoutTable::HeadersOnly );
88   mEmptyModeComboBox->addItem( tr( "Hide Entire Table" ), QgsLayoutTable::HideTable );
89   mEmptyModeComboBox->addItem( tr( "Show Set Message" ), QgsLayoutTable::ShowMessage );
90 
91   mWrapBehaviorComboBox->addItem( tr( "Truncate Text" ), QgsLayoutTable::TruncateText );
92   mWrapBehaviorComboBox->addItem( tr( "Wrap Text" ), QgsLayoutTable::WrapText );
93 
94   mHeaderModeComboBox->addItem( tr( "On First Frame" ), QgsLayoutTable::FirstFrame );
95   mHeaderModeComboBox->addItem( tr( "On All Frames" ), QgsLayoutTable::AllFrames );
96   mHeaderModeComboBox->addItem( tr( "No Header" ), QgsLayoutTable::NoHeaders );
97 
98   mHeaderHAlignmentComboBox->addItem( tr( "Follow Column Alignment" ), QgsLayoutTable::FollowColumn );
99   mHeaderHAlignmentComboBox->addItem( tr( "Left" ), QgsLayoutTable::HeaderLeft );
100   mHeaderHAlignmentComboBox->addItem( tr( "Center" ), QgsLayoutTable::HeaderCenter );
101   mHeaderHAlignmentComboBox->addItem( tr( "Right" ), QgsLayoutTable::HeaderRight );
102 
103   mSourceComboBox->addItem( tr( "Layer Features" ), QgsLayoutItemAttributeTable::LayerAttributes );
104   toggleAtlasSpecificControls( static_cast< bool >( coverageLayer() ) );
105 
106   //update relations combo when relations modified in project
107   connect( QgsProject::instance()->relationManager(), &QgsRelationManager::changed, this, &QgsLayoutAttributeTableWidget::updateRelationsCombo );
108 
109   mLayerComboBox->setFilters( QgsMapLayerProxyModel::VectorLayer );
110   connect( mLayerComboBox, &QgsMapLayerComboBox::layerChanged, this, &QgsLayoutAttributeTableWidget::changeLayer );
111 
112   mComposerMapComboBox->setCurrentLayout( mTable->layout() );
113   mComposerMapComboBox->setItemType( QgsLayoutItemRegistry::LayoutMap );
114   connect( mComposerMapComboBox, &QgsLayoutItemComboBox::itemChanged, this, &QgsLayoutAttributeTableWidget::composerMapChanged );
115 
116   mGridColorButton->setColorDialogTitle( tr( "Select Grid Color" ) );
117   mGridColorButton->setAllowOpacity( true );
118   mGridColorButton->setContext( QStringLiteral( "composer" ) );
119   mGridColorButton->setDefaultColor( Qt::black );
120   mBackgroundColorButton->setColorDialogTitle( tr( "Select Background Color" ) );
121   mBackgroundColorButton->setAllowOpacity( true );
122   mBackgroundColorButton->setContext( QStringLiteral( "composer" ) );
123   mBackgroundColorButton->setShowNoColor( true );
124   mBackgroundColorButton->setNoColorString( tr( "No Background" ) );
125 
126   updateGuiElements();
127 
128   if ( mTable )
129   {
130     connect( mTable, &QgsLayoutMultiFrame::changed, this, &QgsLayoutAttributeTableWidget::updateGuiElements );
131 
132     // repopulate relations combo box if atlas layer changes
133     connect( &mTable->layout()->reportContext(), &QgsLayoutReportContext::layerChanged,
134              this, &QgsLayoutAttributeTableWidget::atlasToggled );
135 
136     if ( QgsLayoutAtlas *atlas = layoutAtlas() )
137     {
138       connect( atlas, &QgsLayoutAtlas::toggled, this, &QgsLayoutAttributeTableWidget::atlasToggled );
139       atlasToggled();
140     }
141 
142     mLayerSourceDDBtn->registerExpressionContextGenerator( mTable );
143   }
144 
145   registerDataDefinedButton( mLayerSourceDDBtn, QgsLayoutObject::AttributeTableSourceLayer );
146 
147   //embed widget for general options
148   if ( mFrame )
149   {
150     //add widget for general composer item properties
151     mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, mFrame );
152     mainLayout->addWidget( mItemPropertiesWidget );
153   }
154 
155   connect( mHeaderFontToolButton, &QgsFontButton::changed, this, &QgsLayoutAttributeTableWidget::headerFontChanged );
156   connect( mContentFontToolButton, &QgsFontButton::changed, this, &QgsLayoutAttributeTableWidget::contentFontChanged );
157 }
158 
setReportTypeString(const QString & string)159 void QgsLayoutAttributeTableWidget::setReportTypeString( const QString &string )
160 {
161   mIntersectAtlasCheckBox->setText( tr( "Show only features intersecting %1 feature" ).arg( string ) );
162   const int atlasFeatureIndex = mSourceComboBox->findData( QgsLayoutItemAttributeTable::AtlasFeature );
163   if ( atlasFeatureIndex != -1 )
164   {
165     mSourceComboBox->setItemText( atlasFeatureIndex,  tr( "Current %1 Feature" ).arg( string ) );
166   }
167 }
168 
setMasterLayout(QgsMasterLayoutInterface * masterLayout)169 void QgsLayoutAttributeTableWidget::setMasterLayout( QgsMasterLayoutInterface *masterLayout )
170 {
171   if ( mItemPropertiesWidget )
172     mItemPropertiesWidget->setMasterLayout( masterLayout );
173 }
174 
createExpressionContext() const175 QgsExpressionContext QgsLayoutAttributeTableWidget::createExpressionContext() const
176 {
177   QgsExpressionContext context;
178 
179   // frames include their parent multiframe's context, so prefer that if possible
180   if ( mFrame )
181     context = mFrame->createExpressionContext();
182   else if ( mTable )
183     context = mTable->createExpressionContext();
184 
185   std::unique_ptr< QgsExpressionContextScope > cellScope = std::make_unique< QgsExpressionContextScope >();
186   cellScope->setVariable( QStringLiteral( "row_number" ), 1, true );
187   cellScope->setVariable( QStringLiteral( "column_number" ), 1, true );
188   context.appendScope( cellScope.release() );
189 
190   context.setHighlightedVariables( { QStringLiteral( "row_number" ),
191                                      QStringLiteral( "column_number" )} );
192 
193   return context;
194 }
195 
setNewItem(QgsLayoutItem * item)196 bool QgsLayoutAttributeTableWidget::setNewItem( QgsLayoutItem *item )
197 {
198   QgsLayoutFrame *frame = qobject_cast< QgsLayoutFrame * >( item );
199   if ( !frame )
200     return false;
201 
202   QgsLayoutMultiFrame *multiFrame = frame->multiFrame();
203   if ( !multiFrame )
204     return false;
205 
206   if ( multiFrame->type() != QgsLayoutItemRegistry::LayoutAttributeTable )
207     return false;
208 
209   if ( mTable )
210   {
211     disconnect( mTable, &QgsLayoutObject::changed, this, &QgsLayoutAttributeTableWidget::updateGuiElements );
212   }
213 
214   mTable = qobject_cast< QgsLayoutItemAttributeTable * >( multiFrame );
215   mFrame = frame;
216   mItemPropertiesWidget->setItem( frame );
217 
218   if ( mTable )
219   {
220     connect( mTable, &QgsLayoutObject::changed, this, &QgsLayoutAttributeTableWidget::updateGuiElements );
221   }
222 
223   updateGuiElements();
224 
225   return true;
226 }
227 
228 
mRefreshPushButton_clicked()229 void QgsLayoutAttributeTableWidget::mRefreshPushButton_clicked()
230 {
231   if ( !mTable )
232   {
233     return;
234   }
235 
236   mTable->refreshAttributes();
237 }
238 
mAttributesPushButton_clicked()239 void QgsLayoutAttributeTableWidget::mAttributesPushButton_clicked()
240 {
241   if ( !mTable )
242   {
243     return;
244   }
245 
246   //make deep copy of current columns, so we can restore them in case of cancellation
247   QVector<QgsLayoutTableColumn> currentColumns = mTable->columns();
248   QVector<QgsLayoutTableColumn> currentSortColumns = mTable->sortColumns();
249 
250   mTable->beginCommand( tr( "Change Table Attributes" ) );
251 
252   //temporarily block updates for the window, to stop table trying to repaint under windows (#11462)
253   window()->setUpdatesEnabled( false );
254 
255   QgsLayoutAttributeSelectionDialog d( mTable, mTable->sourceLayer(), this );
256   if ( d.exec() == QDialog::Accepted )
257   {
258     mTable->refreshAttributes();
259     //safe to unblock updates
260     window()->setUpdatesEnabled( true );
261     mTable->update();
262     mTable->endCommand();
263 
264     //clear currentColumns to free memory
265     currentColumns.clear();
266     currentSortColumns.clear();
267   }
268   else
269   {
270     //undo changes
271     mTable->setColumns( currentColumns );
272     mTable->setSortColumns( currentSortColumns );
273     window()->setUpdatesEnabled( true );
274     mTable->cancelCommand();
275   }
276 }
277 
composerMapChanged(QgsLayoutItem * item)278 void QgsLayoutAttributeTableWidget::composerMapChanged( QgsLayoutItem *item )
279 {
280   if ( !mTable )
281   {
282     return;
283   }
284 
285   mTable->beginCommand( tr( "Change Table Map" ) );
286   mTable->setMap( qobject_cast< QgsLayoutItemMap * >( item ) );
287   mTable->update();
288   mTable->endCommand();
289 }
290 
mMaximumRowsSpinBox_valueChanged(int i)291 void QgsLayoutAttributeTableWidget::mMaximumRowsSpinBox_valueChanged( int i )
292 {
293   if ( !mTable )
294   {
295     return;
296   }
297 
298   mTable->beginCommand( tr( "Change Table Rows" ), QgsLayoutMultiFrame::UndoTableMaximumFeatures );
299   mTable->setMaximumNumberOfFeatures( i );
300   mTable->update();
301   mTable->endCommand();
302 }
303 
mMarginSpinBox_valueChanged(double d)304 void QgsLayoutAttributeTableWidget::mMarginSpinBox_valueChanged( double d )
305 {
306   if ( !mTable )
307   {
308     return;
309   }
310 
311   mTable->beginCommand( tr( "Change Table Margin" ), QgsLayoutMultiFrame::UndoTableMargin );
312   mTable->setCellMargin( d );
313   mTable->endCommand();
314 }
315 
headerFontChanged()316 void QgsLayoutAttributeTableWidget::headerFontChanged()
317 {
318   if ( !mTable )
319     return;
320 
321   mTable->beginCommand( tr( "Change Table Text Format" ) );
322   mTable->setHeaderTextFormat( mHeaderFontToolButton->textFormat() );
323   mTable->endCommand();
324 }
325 
contentFontChanged()326 void QgsLayoutAttributeTableWidget::contentFontChanged()
327 {
328   if ( !mTable )
329   {
330     return;
331   }
332 
333   mTable->beginCommand( tr( "Change Table Text Format" ) );
334   mTable->setContentTextFormat( mContentFontToolButton->textFormat() );
335   mTable->endCommand();
336 }
337 
mGridStrokeWidthSpinBox_valueChanged(double d)338 void QgsLayoutAttributeTableWidget::mGridStrokeWidthSpinBox_valueChanged( double d )
339 {
340   if ( !mTable )
341   {
342     return;
343   }
344 
345   mTable->beginCommand( tr( "Change Table Line Width" ), QgsLayoutMultiFrame::UndoTableGridStrokeWidth );
346   mTable->setGridStrokeWidth( d );
347   mTable->endCommand();
348 }
349 
mGridColorButton_colorChanged(const QColor & newColor)350 void QgsLayoutAttributeTableWidget::mGridColorButton_colorChanged( const QColor &newColor )
351 {
352   if ( !mTable )
353   {
354     return;
355   }
356 
357   mTable->beginCommand( tr( "Change Table Grid Color" ), QgsLayoutMultiFrame::UndoTableGridColor );
358   mTable->setGridColor( newColor );
359   mTable->endCommand();
360 }
361 
mDrawHorizontalGrid_toggled(bool state)362 void QgsLayoutAttributeTableWidget::mDrawHorizontalGrid_toggled( bool state )
363 {
364   if ( !mTable )
365   {
366     return;
367   }
368 
369   mTable->beginCommand( tr( "Toggle Table Grid" ) );
370   mTable->setHorizontalGrid( state );
371   mTable->endCommand();
372 }
373 
mDrawVerticalGrid_toggled(bool state)374 void QgsLayoutAttributeTableWidget::mDrawVerticalGrid_toggled( bool state )
375 {
376   if ( !mTable )
377   {
378     return;
379   }
380 
381   mTable->beginCommand( tr( "Toggled Table Grid" ) );
382   mTable->setVerticalGrid( state );
383   mTable->endCommand();
384 }
385 
mShowGridGroupCheckBox_toggled(bool state)386 void QgsLayoutAttributeTableWidget::mShowGridGroupCheckBox_toggled( bool state )
387 {
388   if ( !mTable )
389   {
390     return;
391   }
392 
393   mTable->beginCommand( tr( "Toggle Table Grid" ) );
394   mTable->setShowGrid( state );
395   mTable->endCommand();
396 }
397 
mBackgroundColorButton_colorChanged(const QColor & newColor)398 void QgsLayoutAttributeTableWidget::mBackgroundColorButton_colorChanged( const QColor &newColor )
399 {
400   if ( !mTable )
401   {
402     return;
403   }
404 
405   mTable->beginCommand( tr( "Change Table Color" ), QgsLayoutMultiFrame::UndoTableBackgroundColor );
406   mTable->setBackgroundColor( newColor );
407   mTable->endCommand();
408 }
409 
updateGuiElements()410 void QgsLayoutAttributeTableWidget::updateGuiElements()
411 {
412   if ( !mTable || !mFrame )
413   {
414     return;
415   }
416 
417   blockAllSignals( true );
418 
419   mSourceComboBox->setCurrentIndex( mSourceComboBox->findData( mTable->source() ) );
420   mRelationsComboBox->setCurrentIndex( mRelationsComboBox->findData( mTable->relationId() ) );
421 
422   //layer combo box
423   if ( mTable->vectorLayer() )
424   {
425     mLayerComboBox->setLayer( mTable->vectorLayer() );
426     if ( mTable->vectorLayer()->geometryType() == QgsWkbTypes::NullGeometry )
427     {
428       //layer has no geometry, so uncheck & disable controls which require geometry
429       mShowOnlyVisibleFeaturesCheckBox->setChecked( false );
430       mShowOnlyVisibleFeaturesCheckBox->setEnabled( false );
431       mComposerMapComboBox->setEnabled( false );
432       mComposerMapLabel->setEnabled( false );
433       mIntersectAtlasCheckBox->setEnabled( false );
434     }
435     else
436     {
437       mShowOnlyVisibleFeaturesCheckBox->setEnabled( true );
438       mComposerMapComboBox->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
439       mComposerMapLabel->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
440       mIntersectAtlasCheckBox->setEnabled( mSourceComboBox->findData( QgsLayoutItemAttributeTable::AtlasFeature ) != -1  && mTable->layout()->reportContext().layer() && mTable->layout()->reportContext().layer()->geometryType() != QgsWkbTypes::NullGeometry );
441     }
442   }
443 
444   mComposerMapComboBox->setItem( mTable->map() );
445   mMaximumRowsSpinBox->setValue( mTable->maximumNumberOfFeatures() );
446   mMarginSpinBox->setValue( mTable->cellMargin() );
447   mGridStrokeWidthSpinBox->setValue( mTable->gridStrokeWidth() );
448   mGridColorButton->setColor( mTable->gridColor() );
449   mDrawHorizontalGrid->setChecked( mTable->horizontalGrid() );
450   mDrawVerticalGrid->setChecked( mTable->verticalGrid() );
451   if ( mTable->showGrid() )
452   {
453     mShowGridGroupCheckBox->setChecked( true );
454   }
455   else
456   {
457     mShowGridGroupCheckBox->setChecked( false );
458   }
459   mBackgroundColorButton->setColor( mTable->backgroundColor() );
460 
461   mHeaderFontToolButton->setTextFormat( mTable->headerTextFormat() );
462   mContentFontToolButton->setTextFormat( mTable->contentTextFormat() );
463 
464   if ( mTable->displayOnlyVisibleFeatures() && mShowOnlyVisibleFeaturesCheckBox->isEnabled() )
465   {
466     mShowOnlyVisibleFeaturesCheckBox->setCheckState( Qt::Checked );
467     mComposerMapComboBox->setEnabled( true );
468     mComposerMapLabel->setEnabled( true );
469   }
470   else
471   {
472     mShowOnlyVisibleFeaturesCheckBox->setCheckState( Qt::Unchecked );
473     mComposerMapComboBox->setEnabled( false );
474     mComposerMapLabel->setEnabled( false );
475   }
476 
477   mUniqueOnlyCheckBox->setChecked( mTable->uniqueRowsOnly() );
478   mIntersectAtlasCheckBox->setChecked( mTable->filterToAtlasFeature() );
479   mFeatureFilterEdit->setText( mTable->featureFilter() );
480   mFeatureFilterCheckBox->setCheckState( mTable->filterFeatures() ? Qt::Checked : Qt::Unchecked );
481   mFeatureFilterEdit->setEnabled( mTable->filterFeatures() );
482   mFeatureFilterButton->setEnabled( mTable->filterFeatures() );
483   mUseConditionalStylingCheckBox->setChecked( mTable->useConditionalStyling() );
484 
485   mHeaderHAlignmentComboBox->setCurrentIndex( mHeaderHAlignmentComboBox->findData( mTable->headerHAlignment() ) );
486   mHeaderModeComboBox->setCurrentIndex( mHeaderModeComboBox->findData( mTable->headerMode() ) );
487 
488   mEmptyModeComboBox->setCurrentIndex( mEmptyModeComboBox->findData( mTable->emptyTableBehavior() ) );
489   mEmptyMessageLineEdit->setText( mTable->emptyTableMessage() );
490   mEmptyMessageLineEdit->setEnabled( mTable->emptyTableBehavior() == QgsLayoutTable::ShowMessage );
491   mEmptyMessageLabel->setEnabled( mTable->emptyTableBehavior() == QgsLayoutTable::ShowMessage );
492   mDrawEmptyCheckBox->setChecked( mTable->showEmptyRows() );
493   mWrapStringLineEdit->setText( mTable->wrapString() );
494   mWrapBehaviorComboBox->setCurrentIndex( mWrapBehaviorComboBox->findData( mTable->wrapBehavior() ) );
495 
496   mResizeModeComboBox->setCurrentIndex( mResizeModeComboBox->findData( mTable->resizeMode() ) );
497   mAddFramePushButton->setEnabled( mTable->resizeMode() == QgsLayoutMultiFrame::UseExistingFrames );
498 
499   mEmptyFrameCheckBox->setChecked( mFrame->hidePageIfEmpty() );
500   mHideEmptyBgCheckBox->setChecked( mFrame->hideBackgroundIfEmpty() );
501 
502   updateDataDefinedButton( mLayerSourceDDBtn );
503 
504   toggleSourceControls();
505 
506   blockAllSignals( false );
507 }
508 
atlasToggled()509 void QgsLayoutAttributeTableWidget::atlasToggled()
510 {
511   // display/hide atlas options in source combobox depending on atlas status
512   // if there's no atlas but there IS a coverageLayer, it's a report export and we should enable the controls
513   const bool atlasEnabled = ( layoutAtlas() && layoutAtlas()->enabled() ) || ( !layoutAtlas() && coverageLayer() );
514 
515 
516   toggleAtlasSpecificControls( atlasEnabled );
517 
518   if ( !mTable )
519     return;
520 
521   whileBlocking( mSourceComboBox )->setCurrentIndex( mSourceComboBox->findData( mTable->source() ) );
522 
523   if ( !atlasEnabled && mTable->filterToAtlasFeature() )
524   {
525     mTable->setFilterToAtlasFeature( false );
526   }
527 }
528 
updateRelationsCombo()529 void QgsLayoutAttributeTableWidget::updateRelationsCombo()
530 {
531   mRelationsComboBox->blockSignals( true );
532   mRelationsComboBox->clear();
533 
534   QgsVectorLayer *atlasLayer = coverageLayer();
535   if ( atlasLayer )
536   {
537     const QList<QgsRelation> relations = QgsProject::instance()->relationManager()->referencedRelations( atlasLayer );
538     for ( const QgsRelation &relation : relations )
539     {
540       mRelationsComboBox->addItem( relation.name(), relation.id() );
541     }
542     if ( mTable )
543     {
544       mRelationsComboBox->setCurrentIndex( mRelationsComboBox->findData( mTable->relationId() ) );
545     }
546   }
547 
548   mRelationsComboBox->blockSignals( false );
549 }
550 
toggleAtlasSpecificControls(const bool atlasEnabled)551 void QgsLayoutAttributeTableWidget::toggleAtlasSpecificControls( const bool atlasEnabled )
552 {
553   if ( !atlasEnabled )
554   {
555     if ( mTable->source() == QgsLayoutItemAttributeTable::AtlasFeature )
556     {
557       mTable->setSource( QgsLayoutItemAttributeTable::LayerAttributes );
558     }
559     mSourceComboBox->removeItem( mSourceComboBox->findData( QgsLayoutItemAttributeTable::AtlasFeature ) );
560     mSourceComboBox->removeItem( mSourceComboBox->findData( QgsLayoutItemAttributeTable::RelationChildren ) );
561     mRelationsComboBox->blockSignals( true );
562     mRelationsComboBox->setEnabled( false );
563     mRelationsComboBox->clear();
564     mRelationsComboBox->blockSignals( false );
565     mIntersectAtlasCheckBox->setEnabled( false );
566   }
567   else
568   {
569     if ( mSourceComboBox->findData( QgsLayoutItemAttributeTable::AtlasFeature ) == -1 )
570     {
571       //add missing atlasfeature option to combobox
572       mSourceComboBox->addItem( tr( "Current Atlas Feature" ), QgsLayoutItemAttributeTable::AtlasFeature );
573     }
574     if ( mSourceComboBox->findData( QgsLayoutItemAttributeTable::RelationChildren ) == -1 )
575     {
576       //add missing relation children option to combobox
577       mSourceComboBox->addItem( tr( "Relation Children" ), QgsLayoutItemAttributeTable::RelationChildren );
578     }
579 
580     //add relations for coverage layer
581     updateRelationsCombo();
582     mRelationsComboBox->setEnabled( true );
583     mIntersectAtlasCheckBox->setEnabled( mTable->layout()->reportContext().layer() && mTable->layout()->reportContext().layer()->geometryType() != QgsWkbTypes::NullGeometry );
584   }
585 }
586 
blockAllSignals(bool b)587 void QgsLayoutAttributeTableWidget::blockAllSignals( bool b )
588 {
589   mSourceComboBox->blockSignals( b );
590   mLayerComboBox->blockSignals( b );
591   mComposerMapComboBox->blockSignals( b );
592   mMaximumRowsSpinBox->blockSignals( b );
593   mMarginSpinBox->blockSignals( b );
594   mGridColorButton->blockSignals( b );
595   mGridStrokeWidthSpinBox->blockSignals( b );
596   mBackgroundColorButton->blockSignals( b );
597   mDrawHorizontalGrid->blockSignals( b );
598   mDrawVerticalGrid->blockSignals( b );
599   mShowGridGroupCheckBox->blockSignals( b );
600   mShowOnlyVisibleFeaturesCheckBox->blockSignals( b );
601   mUniqueOnlyCheckBox->blockSignals( b );
602   mIntersectAtlasCheckBox->blockSignals( b );
603   mFeatureFilterEdit->blockSignals( b );
604   mFeatureFilterCheckBox->blockSignals( b );
605   mHeaderHAlignmentComboBox->blockSignals( b );
606   mHeaderModeComboBox->blockSignals( b );
607   mResizeModeComboBox->blockSignals( b );
608   mRelationsComboBox->blockSignals( b );
609   mEmptyModeComboBox->blockSignals( b );
610   mEmptyMessageLineEdit->blockSignals( b );
611   mEmptyFrameCheckBox->blockSignals( b );
612   mHideEmptyBgCheckBox->blockSignals( b );
613   mDrawEmptyCheckBox->blockSignals( b );
614   mWrapStringLineEdit->blockSignals( b );
615   mWrapBehaviorComboBox->blockSignals( b );
616   mContentFontToolButton->blockSignals( b );
617   mHeaderFontToolButton->blockSignals( b );
618 }
619 
setMaximumNumberOfFeatures(int n)620 void QgsLayoutAttributeTableWidget::setMaximumNumberOfFeatures( int n )
621 {
622   whileBlocking( mMaximumRowsSpinBox )->setValue( n );
623 }
624 
mShowOnlyVisibleFeaturesCheckBox_stateChanged(int state)625 void QgsLayoutAttributeTableWidget::mShowOnlyVisibleFeaturesCheckBox_stateChanged( int state )
626 {
627   if ( !mTable )
628   {
629     return;
630   }
631 
632   mTable->beginCommand( tr( "Toggle Visible Features Only" ) );
633   const bool showOnlyVisibleFeatures = ( state == Qt::Checked );
634   mTable->setDisplayOnlyVisibleFeatures( showOnlyVisibleFeatures );
635   mTable->update();
636   mTable->endCommand();
637 
638   //enable/disable map combobox based on state of checkbox
639   mComposerMapComboBox->setEnabled( state == Qt::Checked );
640   mComposerMapLabel->setEnabled( state == Qt::Checked );
641 }
642 
mUniqueOnlyCheckBox_stateChanged(int state)643 void QgsLayoutAttributeTableWidget::mUniqueOnlyCheckBox_stateChanged( int state )
644 {
645   if ( !mTable )
646   {
647     return;
648   }
649 
650   mTable->beginCommand( tr( "Toggle Table Filter Duplicates" ) );
651   mTable->setUniqueRowsOnly( state == Qt::Checked );
652   mTable->update();
653   mTable->endCommand();
654 }
655 
mEmptyFrameCheckBox_toggled(bool checked)656 void QgsLayoutAttributeTableWidget::mEmptyFrameCheckBox_toggled( bool checked )
657 {
658   if ( !mFrame )
659   {
660     return;
661   }
662 
663   mFrame->beginCommand( tr( "Toggle Empty Frame Mode" ) );
664   mFrame->setHidePageIfEmpty( checked );
665   mFrame->endCommand();
666 }
667 
mHideEmptyBgCheckBox_toggled(bool checked)668 void QgsLayoutAttributeTableWidget::mHideEmptyBgCheckBox_toggled( bool checked )
669 {
670   if ( !mFrame )
671   {
672     return;
673   }
674 
675   mFrame->beginCommand( tr( "Toggle Background Display" ) );
676   mFrame->setHideBackgroundIfEmpty( checked );
677   mFrame->endCommand();
678 }
679 
mIntersectAtlasCheckBox_stateChanged(int state)680 void QgsLayoutAttributeTableWidget::mIntersectAtlasCheckBox_stateChanged( int state )
681 {
682   if ( !mTable )
683   {
684     return;
685   }
686 
687   mTable->beginCommand( tr( "Toggle Table Atlas Filter" ) );
688   const bool filterToAtlas = ( state == Qt::Checked );
689   mTable->setFilterToAtlasFeature( filterToAtlas );
690   mTable->update();
691   mTable->endCommand();
692 }
693 
mFeatureFilterCheckBox_stateChanged(int state)694 void QgsLayoutAttributeTableWidget::mFeatureFilterCheckBox_stateChanged( int state )
695 {
696   if ( !mTable )
697   {
698     return;
699   }
700 
701   if ( state == Qt::Checked )
702   {
703     mFeatureFilterEdit->setEnabled( true );
704     mFeatureFilterButton->setEnabled( true );
705   }
706   else
707   {
708     mFeatureFilterEdit->setEnabled( false );
709     mFeatureFilterButton->setEnabled( false );
710   }
711 
712   mTable->beginCommand( tr( "Toggle Table Feature Filter" ) );
713   mTable->setFilterFeatures( state == Qt::Checked );
714   mTable->update();
715   mTable->endCommand();
716 }
717 
mFeatureFilterEdit_editingFinished()718 void QgsLayoutAttributeTableWidget::mFeatureFilterEdit_editingFinished()
719 {
720   if ( !mTable )
721   {
722     return;
723   }
724 
725   mTable->beginCommand( tr( "Change Table Feature Filter" ) );
726   mTable->setFeatureFilter( mFeatureFilterEdit->text() );
727   mTable->update();
728   mTable->endCommand();
729 }
730 
mFeatureFilterButton_clicked()731 void QgsLayoutAttributeTableWidget::mFeatureFilterButton_clicked()
732 {
733   if ( !mTable )
734   {
735     return;
736   }
737 
738   const QgsExpressionContext context = mTable->createExpressionContext();
739   QgsExpressionBuilderDialog exprDlg( mTable->sourceLayer(), mFeatureFilterEdit->text(), this, QStringLiteral( "generic" ), context );
740   exprDlg.setWindowTitle( tr( "Expression Based Filter" ) );
741   if ( exprDlg.exec() == QDialog::Accepted )
742   {
743     const QString expression = exprDlg.expressionText();
744     if ( !expression.isEmpty() )
745     {
746       mFeatureFilterEdit->setText( expression );
747       mTable->beginCommand( tr( "Change Table Feature Filter" ) );
748       mTable->setFeatureFilter( mFeatureFilterEdit->text() );
749       mTable->update();
750       mTable->endCommand();
751     }
752   }
753 }
754 
mHeaderHAlignmentComboBox_currentIndexChanged(int)755 void QgsLayoutAttributeTableWidget::mHeaderHAlignmentComboBox_currentIndexChanged( int )
756 {
757   if ( !mTable )
758   {
759     return;
760   }
761 
762   mTable->beginCommand( tr( "Change Table Alignment" ) );
763   mTable->setHeaderHAlignment( static_cast<  QgsLayoutTable::HeaderHAlignment >( mHeaderHAlignmentComboBox->currentData().toInt() ) );
764   mTable->endCommand();
765 }
766 
mHeaderModeComboBox_currentIndexChanged(int)767 void QgsLayoutAttributeTableWidget::mHeaderModeComboBox_currentIndexChanged( int )
768 {
769   if ( !mTable )
770   {
771     return;
772   }
773 
774   mTable->beginCommand( tr( "Change Table Header Mode" ) );
775   mTable->setHeaderMode( static_cast< QgsLayoutTable::HeaderMode >( mHeaderModeComboBox->currentData().toInt() ) );
776   mTable->endCommand();
777 }
778 
mWrapStringLineEdit_editingFinished()779 void QgsLayoutAttributeTableWidget::mWrapStringLineEdit_editingFinished()
780 {
781   if ( !mTable )
782   {
783     return;
784   }
785 
786   mTable->beginCommand( tr( "Change Table Wrap String" ) );
787   mTable->setWrapString( mWrapStringLineEdit->text() );
788   mTable->endCommand();
789 }
790 
changeLayer(QgsMapLayer * layer)791 void QgsLayoutAttributeTableWidget::changeLayer( QgsMapLayer *layer )
792 {
793   if ( !mTable )
794   {
795     return;
796   }
797 
798   QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
799   if ( !vl )
800   {
801     return;
802   }
803 
804   mTable->beginCommand( tr( "Change Table Layer" ) );
805   mTable->setVectorLayer( vl );
806   mTable->update();
807   mTable->endCommand();
808 
809   mContentFontToolButton->setLayer( vl );
810   mHeaderFontToolButton->setLayer( vl );
811 
812   if ( vl->geometryType() == QgsWkbTypes::NullGeometry )
813   {
814     //layer has no geometry, so uncheck & disable controls which require geometry
815     mShowOnlyVisibleFeaturesCheckBox->setChecked( false );
816     mShowOnlyVisibleFeaturesCheckBox->setEnabled( false );
817     mComposerMapComboBox->setEnabled( false );
818     mComposerMapLabel->setEnabled( false );
819     mIntersectAtlasCheckBox->setEnabled( false );
820   }
821   else
822   {
823     mShowOnlyVisibleFeaturesCheckBox->setEnabled( true );
824     mComposerMapComboBox->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
825     mComposerMapLabel->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
826     mIntersectAtlasCheckBox->setEnabled( mSourceComboBox->findData( QgsLayoutItemAttributeTable::AtlasFeature ) != -1  && mTable->layout()->reportContext().layer() && mTable->layout()->reportContext().layer()->geometryType() != QgsWkbTypes::NullGeometry );
827   }
828 }
829 
mAddFramePushButton_clicked()830 void QgsLayoutAttributeTableWidget::mAddFramePushButton_clicked()
831 {
832   if ( !mTable || !mFrame )
833   {
834     return;
835   }
836 
837   //create a new frame based on the current frame
838   QPointF pos = mFrame->pos();
839   //shift new frame so that it sits 10 units below current frame
840   pos.ry() += mFrame->rect().height() + 10;
841 
842   QgsLayoutFrame *newFrame = mTable->createNewFrame( mFrame, pos, mFrame->rect().size() );
843   mTable->recalculateFrameSizes();
844 
845   //set new frame as selection
846   if ( QgsLayout *layout = mTable->layout() )
847   {
848     layout->setSelectedItem( newFrame );
849   }
850 }
851 
mResizeModeComboBox_currentIndexChanged(int index)852 void QgsLayoutAttributeTableWidget::mResizeModeComboBox_currentIndexChanged( int index )
853 {
854   if ( !mTable )
855   {
856     return;
857   }
858 
859   mTable->beginCommand( tr( "Change Resize Mode" ) );
860   mTable->setResizeMode( static_cast< QgsLayoutMultiFrame::ResizeMode >( mResizeModeComboBox->itemData( index ).toInt() ) );
861   mTable->endCommand();
862 
863   mAddFramePushButton->setEnabled( mTable->resizeMode() == QgsLayoutMultiFrame::UseExistingFrames );
864 }
865 
mSourceComboBox_currentIndexChanged(int index)866 void QgsLayoutAttributeTableWidget::mSourceComboBox_currentIndexChanged( int index )
867 {
868   if ( !mTable )
869   {
870     return;
871   }
872 
873   mTable->beginCommand( tr( "Change Table Source" ) );
874   mTable->setSource( static_cast< QgsLayoutItemAttributeTable::ContentSource >( mSourceComboBox->itemData( index ).toInt() ) );
875   mTable->endCommand();
876 
877   toggleSourceControls();
878 }
879 
mRelationsComboBox_currentIndexChanged(int index)880 void QgsLayoutAttributeTableWidget::mRelationsComboBox_currentIndexChanged( int index )
881 {
882   if ( !mTable )
883   {
884     return;
885   }
886 
887   mTable->beginCommand( tr( "Change Table Source Relation" ) );
888   mTable->setRelationId( mRelationsComboBox->itemData( index ).toString() );
889   mTable->endCommand();
890 }
891 
mEmptyModeComboBox_currentIndexChanged(int index)892 void QgsLayoutAttributeTableWidget::mEmptyModeComboBox_currentIndexChanged( int index )
893 {
894   if ( !mTable )
895   {
896     return;
897   }
898 
899   mTable->beginCommand( tr( "Change Empty Table Behavior" ) );
900   mTable->setEmptyTableBehavior( static_cast< QgsLayoutTable::EmptyTableMode >( mEmptyModeComboBox->itemData( index ).toInt() ) );
901   mTable->endCommand();
902   mEmptyMessageLineEdit->setEnabled( mTable->emptyTableBehavior() == QgsLayoutTable::ShowMessage );
903   mEmptyMessageLabel->setEnabled( mTable->emptyTableBehavior() == QgsLayoutTable::ShowMessage );
904 }
905 
mWrapBehaviorComboBox_currentIndexChanged(int index)906 void QgsLayoutAttributeTableWidget::mWrapBehaviorComboBox_currentIndexChanged( int index )
907 {
908   if ( !mTable )
909   {
910     return;
911   }
912 
913   mTable->beginCommand( tr( "Change Table Wrap Mode" ) );
914   mTable->setWrapBehavior( static_cast< QgsLayoutTable::WrapBehavior >( mWrapBehaviorComboBox->itemData( index ).toInt() ) );
915   mTable->endCommand();
916 }
917 
mAdvancedCustomizationButton_clicked()918 void QgsLayoutAttributeTableWidget::mAdvancedCustomizationButton_clicked()
919 {
920   if ( !mTable )
921   {
922     return;
923   }
924 
925   QgsLayoutTableBackgroundColorsDialog d( mTable, this );
926   d.exec();
927 }
928 
useConditionalStylingChanged(bool checked)929 void QgsLayoutAttributeTableWidget::useConditionalStylingChanged( bool checked )
930 {
931   if ( !mTable )
932   {
933     return;
934   }
935 
936   mTable->beginCommand( tr( "Toggle Table Conditional Styling" ) );
937   mTable->setUseConditionalStyling( checked );
938   mTable->update();
939   mTable->endCommand();
940 }
941 
mDrawEmptyCheckBox_toggled(bool checked)942 void QgsLayoutAttributeTableWidget::mDrawEmptyCheckBox_toggled( bool checked )
943 {
944   if ( !mTable )
945   {
946     return;
947   }
948 
949   mTable->beginCommand( tr( "Change Show Empty Rows" ) );
950   mTable->setShowEmptyRows( checked );
951   mTable->endCommand();
952 }
953 
mEmptyMessageLineEdit_editingFinished()954 void QgsLayoutAttributeTableWidget::mEmptyMessageLineEdit_editingFinished()
955 {
956   if ( !mTable )
957   {
958     return;
959   }
960 
961   mTable->beginCommand( tr( "Change Empty Table Message" ) );
962   mTable->setEmptyTableMessage( mEmptyMessageLineEdit->text() );
963   mTable->endCommand();
964 }
965 
toggleSourceControls()966 void QgsLayoutAttributeTableWidget::toggleSourceControls()
967 {
968   switch ( mTable->source() )
969   {
970     case QgsLayoutItemAttributeTable::LayerAttributes:
971       mLayerComboBox->setEnabled( true );
972       mLayerComboBox->setVisible( true );
973       mLayerSourceDDBtn->setVisible( true );
974       mLayerLabel->setVisible( true );
975       mRelationsComboBox->setEnabled( false );
976       mRelationsComboBox->setVisible( false );
977       mRelationLabel->setVisible( false );
978       mMaximumRowsSpinBox->setEnabled( true );
979       mMaxNumFeaturesLabel->setEnabled( true );
980       mShowOnlyVisibleFeaturesCheckBox->setEnabled( mTable->vectorLayer() && mTable->vectorLayer()->geometryType() != QgsWkbTypes::NullGeometry );
981       mShowOnlyVisibleFeaturesCheckBox->setChecked( mTable->vectorLayer() && mTable->vectorLayer()->geometryType() != QgsWkbTypes::NullGeometry && mTable->displayOnlyVisibleFeatures() );
982       mComposerMapComboBox->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
983       mComposerMapLabel->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
984       mIntersectAtlasCheckBox->setEnabled( mTable->vectorLayer() && mTable->vectorLayer()->geometryType() != QgsWkbTypes::NullGeometry
985                                            && mSourceComboBox->findData( QgsLayoutItemAttributeTable::AtlasFeature ) != -1 && mTable->layout()->reportContext().layer() && mTable->layout()->reportContext().layer()->geometryType() != QgsWkbTypes::NullGeometry );
986       break;
987     case QgsLayoutItemAttributeTable::AtlasFeature:
988       mLayerComboBox->setEnabled( false );
989       mLayerComboBox->setVisible( false );
990       mLayerSourceDDBtn->setVisible( false );
991       mLayerLabel->setVisible( false );
992       mRelationsComboBox->setEnabled( false );
993       mRelationsComboBox->setVisible( false );
994       mRelationLabel->setVisible( false );
995       mMaximumRowsSpinBox->setEnabled( false );
996       mMaxNumFeaturesLabel->setEnabled( false );
997       mShowOnlyVisibleFeaturesCheckBox->setEnabled( mTable->sourceLayer() && mTable->sourceLayer()->geometryType() != QgsWkbTypes::NullGeometry );
998       mShowOnlyVisibleFeaturesCheckBox->setChecked( mTable->sourceLayer() && mTable->sourceLayer()->geometryType() != QgsWkbTypes::NullGeometry && mTable->displayOnlyVisibleFeatures() );
999       mComposerMapComboBox->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
1000       mComposerMapLabel->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
1001       mIntersectAtlasCheckBox->setEnabled( false );
1002       break;
1003     case QgsLayoutItemAttributeTable::RelationChildren:
1004       mLayerComboBox->setEnabled( false );
1005       mLayerComboBox->setVisible( false );
1006       mLayerLabel->setVisible( false );
1007       mLayerSourceDDBtn->setVisible( false );
1008       mRelationsComboBox->setEnabled( true );
1009       mRelationsComboBox->setVisible( true );
1010       mRelationLabel->setVisible( true );
1011       mMaximumRowsSpinBox->setEnabled( true );
1012       mMaxNumFeaturesLabel->setEnabled( true );
1013       //it's missing the check for null geometry of the referencing layer
1014       mShowOnlyVisibleFeaturesCheckBox->setEnabled( true );
1015       mComposerMapComboBox->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
1016       mComposerMapLabel->setEnabled( mShowOnlyVisibleFeaturesCheckBox->isChecked() );
1017       mIntersectAtlasCheckBox->setEnabled( mSourceComboBox->findData( QgsLayoutItemAttributeTable::AtlasFeature ) != -1 && mTable->layout()->reportContext().layer() && mTable->layout()->reportContext().layer()->geometryType() != QgsWkbTypes::NullGeometry );
1018       break;
1019   }
1020 }
1021