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