QGIS API Documentation  2.99.0-Master (9fdd060)
qgsdualview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdualview.cpp
3  --------------------------------------
4  Date : 10.2.2013
5  Copyright : (C) 2013 Matthias Kuhn
6  Email : matthias at opengis dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsapplication.h"
17 #include "qgsactionmanager.h"
18 #include "qgsattributetablemodel.h"
19 #include "qgsdualview.h"
21 #include "qgsfeaturelistmodel.h"
23 #include "qgsmapcanvas.h"
25 #include "qgsmessagelog.h"
26 #include "qgsvectordataprovider.h"
27 #include "qgsvectorlayercache.h"
30 #include "qgssettings.h"
31 #include "qgsscrollarea.h"
32 #include "qgsgui.h"
33 
34 #include <QClipboard>
35 #include <QDialog>
36 #include <QMenu>
37 #include <QMessageBox>
38 #include <QProgressDialog>
39 #include <QGroupBox>
40 #include <QInputDialog>
41 
42 QgsDualView::QgsDualView( QWidget *parent )
43  : QStackedWidget( parent )
44 {
45  setupUi( this );
46  connect( mFeatureList, &QgsFeatureListView::aboutToChangeEditSelection, this, &QgsDualView::mFeatureList_aboutToChangeEditSelection );
47  connect( mFeatureList, &QgsFeatureListView::currentEditSelectionChanged, this, &QgsDualView::mFeatureList_currentEditSelectionChanged );
48 
49  mConditionalFormatWidget->hide();
50 
51 
52  mPreviewColumnsMenu = new QMenu( this );
53  mActionPreviewColumnsMenu->setMenu( mPreviewColumnsMenu );
54 
55  // Set preview icon
56  mActionExpressionPreview->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) ) );
57 
58  // Connect layer list preview signals
59  connect( mActionExpressionPreview, &QAction::triggered, this, &QgsDualView::previewExpressionBuilder );
60  connect( mFeatureList, &QgsFeatureListView::displayExpressionChanged, this, &QgsDualView::previewExpressionChanged );
61 }
62 
63 void QgsDualView::init( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, const QgsAttributeEditorContext &context, bool loadFeatures )
64 {
65  mMapCanvas = mapCanvas;
66 
67  if ( !layer )
68  return;
69 
70  mLayer = layer;
71 
72  mEditorContext = context;
73 
74  connect( mTableView, &QgsAttributeTableView::willShowContextMenu, this, &QgsDualView::viewWillShowContextMenu );
75  mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
76  connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &QgsDualView::showViewHeaderMenu );
77  connect( mTableView, &QgsAttributeTableView::columnResized, this, &QgsDualView::tableColumnResized );
78 
79  initLayerCache( !( request.flags() & QgsFeatureRequest::NoGeometry ) || !request.filterRect().isNull() );
80  initModels( mapCanvas, request, loadFeatures );
81 
82  mConditionalFormatWidget->setLayer( mLayer );
83 
84  mTableView->setModel( mFilterModel );
85  mFeatureList->setModel( mFeatureListModel );
86  delete mAttributeForm;
87  mAttributeForm = new QgsAttributeForm( mLayer, QgsFeature(), mEditorContext );
88  if ( !context.parentContext() )
89  {
90  mAttributeEditorScrollArea = new QgsScrollArea();
91  mAttributeEditorScrollArea->setWidgetResizable( true );
92  mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea );
93  mAttributeEditorScrollArea->setWidget( mAttributeForm );
94  }
95  else
96  {
97  mAttributeEditor->layout()->addWidget( mAttributeForm );
98  }
99 
100  connect( mAttributeForm, &QgsAttributeForm::attributeChanged, this, &QgsDualView::featureFormAttributeChanged );
101  connect( mAttributeForm, &QgsAttributeForm::modeChanged, this, &QgsDualView::formModeChanged );
102  connect( mMasterModel, &QgsAttributeTableModel::modelChanged, mAttributeForm, &QgsAttributeForm::refreshFeature );
104  connect( mFilterModel, &QgsAttributeTableFilterModel::sortColumnChanged, this, &QgsDualView::onSortColumnChanged );
105 
106  if ( mFeatureListPreviewButton->defaultAction() )
107  mFeatureList->setDisplayExpression( mDisplayExpression );
108  else
109  columnBoxInit();
110 
111  // This slows down load of the attribute table heaps and uses loads of memory.
112  //mTableView->resizeColumnsToContents();
113 
114  mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) );
115 }
116 
117 void QgsDualView::columnBoxInit()
118 {
119  // load fields
120  QList<QgsField> fields = mLayer->fields().toList();
121 
122  QString defaultField;
123 
124  // default expression: saved value
125  QString displayExpression = mLayer->displayExpression();
126 
127  if ( displayExpression.isEmpty() )
128  {
129  // ... there isn't really much to display
130  displayExpression = QStringLiteral( "'[Please define preview text]'" );
131  }
132 
133  mFeatureListPreviewButton->addAction( mActionExpressionPreview );
134  mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
135 
136  Q_FOREACH ( const QgsField &field, fields )
137  {
138  int fieldIndex = mLayer->fields().lookupField( field.name() );
139  if ( fieldIndex == -1 )
140  continue;
141 
142  QString fieldName = field.name();
143  if ( QgsGui::editorWidgetRegistry()->findBest( mLayer, fieldName ).type() != QLatin1String( "Hidden" ) )
144  {
145  QIcon icon = mLayer->fields().iconForField( fieldIndex );
146  QString text = mLayer->attributeDisplayName( fieldIndex );
147 
148  // Generate action for the preview popup button of the feature list
149  QAction *previewAction = new QAction( icon, text, mFeatureListPreviewButton );
150  connect( previewAction, &QAction::triggered, this, [ = ] { previewColumnChanged( previewAction, fieldName ); } );
151  mPreviewColumnsMenu->addAction( previewAction );
152 
153  if ( text == defaultField )
154  {
155  mFeatureListPreviewButton->setDefaultAction( previewAction );
156  }
157  }
158  }
159 
160  QAction *sortByPreviewExpression = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "sort.svg" ) ), tr( "Sort by preview expression" ), this );
161  connect( sortByPreviewExpression, &QAction::triggered, this, &QgsDualView::sortByPreviewExpression );
162  mFeatureListPreviewButton->addAction( sortByPreviewExpression );
163 
164  QAction *separator = new QAction( mFeatureListPreviewButton );
165  separator->setSeparator( true );
166  mFeatureListPreviewButton->addAction( separator );
167  restoreRecentDisplayExpressions();
168 
169  // If there is no single field found as preview
170  if ( !mFeatureListPreviewButton->defaultAction() )
171  {
172  mFeatureList->setDisplayExpression( displayExpression );
173  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
174  setDisplayExpression( mFeatureList->displayExpression() );
175  }
176  else
177  {
178  mFeatureListPreviewButton->defaultAction()->trigger();
179  }
180 }
181 
183 {
184  setCurrentIndex( view );
185 }
186 
188 {
189  return static_cast< QgsDualView::ViewMode >( currentIndex() );
190 }
191 
193 {
194  // cleanup any existing connections
195  switch ( mFilterModel->filterMode() )
196  {
198  disconnect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
199  break;
200 
204  break;
205 
207  disconnect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
208  break;
209  }
210 
211  QgsFeatureRequest r = mMasterModel->request();
212  bool needsGeometry = filterMode == QgsAttributeTableFilterModel::ShowVisible;
213 
214  bool requiresTableReload = ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) // previous request was subset
215  || ( needsGeometry && r.flags() & QgsFeatureRequest::NoGeometry ) // no geometry for last request
216  || ( mMasterModel->rowCount() == 0 ); // no features
217 
218  if ( !needsGeometry )
220  else
224  r.disableFilter();
225 
226  // setup new connections and filter request parameters
227  switch ( filterMode )
228  {
230  connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
231  if ( mMapCanvas )
232  {
233  QgsRectangle rect = mMapCanvas->mapSettings().mapToLayerCoordinates( mLayer, mMapCanvas->extent() );
234  r.setFilterRect( rect );
235  }
236  break;
237 
241  break;
242 
244  connect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
245  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
246  break;
247  }
248 
249  if ( requiresTableReload )
250  {
251  mMasterModel->setRequest( r );
252  whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry );
253  mMasterModel->loadLayer();
254  }
255 
256  //update filter model
257  mFilterModel->setFilterMode( filterMode );
258  emit filterChanged();
259 }
260 
261 void QgsDualView::setSelectedOnTop( bool selectedOnTop )
262 {
263  mFilterModel->setSelectedOnTop( selectedOnTop );
264 }
265 
266 void QgsDualView::initLayerCache( bool cacheGeometry )
267 {
268  // Initialize the cache
269  QgsSettings settings;
270  int cacheSize = settings.value( QStringLiteral( "qgis/attributeTableRowCache" ), "10000" ).toInt();
271  mLayerCache = new QgsVectorLayerCache( mLayer, cacheSize, this );
272  mLayerCache->setCacheGeometry( cacheGeometry );
273  if ( 0 == cacheSize || 0 == ( QgsVectorDataProvider::SelectAtId & mLayer->dataProvider()->capabilities() ) )
274  {
275  connect( mLayerCache, &QgsVectorLayerCache::invalidated, this, &QgsDualView::rebuildFullLayerCache );
276  rebuildFullLayerCache();
277  }
278 }
279 
280 void QgsDualView::initModels( QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, bool loadFeatures )
281 {
282  delete mFeatureListModel;
283  delete mFilterModel;
284  delete mMasterModel;
285 
286  mMasterModel = new QgsAttributeTableModel( mLayerCache, this );
287  mMasterModel->setRequest( request );
288  mMasterModel->setEditorContext( mEditorContext );
289  mMasterModel->setExtraColumns( 1 ); // Add one extra column which we can "abuse" as an action column
290 
291  connect( mMasterModel, &QgsAttributeTableModel::progress, this, &QgsDualView::progress );
292  connect( mMasterModel, &QgsAttributeTableModel::finished, this, &QgsDualView::finished );
293 
295 
296  if ( loadFeatures )
297  mMasterModel->loadLayer();
298 
299  mFilterModel = new QgsAttributeTableFilterModel( mapCanvas, mMasterModel, mMasterModel );
300 
301  // The following connections to invalidate() are necessary to keep the filter model in sync
302  // see regression https://issues.qgis.org/issues/15974
303  connect( mMasterModel, &QgsAttributeTableModel::rowsRemoved, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
304  connect( mMasterModel, &QgsAttributeTableModel::rowsInserted, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
305 
307 
308  mFeatureListModel = new QgsFeatureListModel( mFilterModel, mFilterModel );
309 }
310 
311 void QgsDualView::restoreRecentDisplayExpressions()
312 {
313  const QVariantList previewExpressions = mLayer->customProperty( QStringLiteral( "dualview/previewExpressions" ) ).toList();
314 
315  for ( const QVariant &previewExpression : previewExpressions )
316  insertRecentlyUsedDisplayExpression( previewExpression.toString() );
317 }
318 
319 void QgsDualView::saveRecentDisplayExpressions() const
320 {
321  QList<QAction *> actions = mFeatureListPreviewButton->actions();
322 
323  // Remove existing same action
324  int index = actions.indexOf( mLastDisplayExpressionAction );
325  if ( index != -1 )
326  {
327  QVariantList previewExpressions;
328  for ( ; index < actions.length(); ++index )
329  {
330  QAction *action = actions.at( index );
331  previewExpressions << action->property( "previewExpression" );
332  }
333 
334  mLayer->setCustomProperty( QStringLiteral( "dualview/previewExpressions" ), previewExpressions );
335  }
336 }
337 
338 void QgsDualView::setDisplayExpression( const QString &expression )
339 {
340  mDisplayExpression = expression;
341  insertRecentlyUsedDisplayExpression( expression );
342 }
343 
344 void QgsDualView::insertRecentlyUsedDisplayExpression( const QString &expression )
345 {
346  QList<QAction *> actions = mFeatureListPreviewButton->actions();
347 
348  // Remove existing same action
349  int index = actions.indexOf( mLastDisplayExpressionAction );
350  if ( index != -1 )
351  {
352  for ( int i = 0; index + i < actions.length(); ++i )
353  {
354  QAction *action = actions.at( index );
355  if ( action->text() == expression || i >= 9 )
356  {
357  if ( action == mLastDisplayExpressionAction )
358  mLastDisplayExpressionAction = nullptr;
359  mFeatureListPreviewButton->removeAction( action );
360  }
361  else
362  {
363  if ( !mLastDisplayExpressionAction )
364  mLastDisplayExpressionAction = action;
365  }
366  }
367  }
368 
369  QString name = expression;
370  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) );
371  if ( expression.startsWith( QLatin1String( "COALESCE( \"" ) ) && expression.endsWith( QLatin1String( ", '<NULL>' )" ) ) )
372  {
373  name = expression.mid( 11, expression.length() - 24 ); // Numbers calculated from the COALESCE / <NULL> parts
374 
375  int fieldIndex = mLayer->fields().indexOf( name );
376  if ( fieldIndex != -1 )
377  {
378  name = mLayer->attributeDisplayName( fieldIndex );
379  icon = mLayer->fields().iconForField( fieldIndex );
380  }
381  else
382  {
383  name = expression;
384  }
385  }
386 
387  QAction *previewAction = new QAction( icon, name, mFeatureListPreviewButton );
388  previewAction->setProperty( "previewExpression", expression );
389  connect( previewAction, &QAction::triggered, this, [expression, this]( bool )
390  {
391  setDisplayExpression( expression );
392  mFeatureListPreviewButton->setText( expression );
393  }
394  );
395 
396  mFeatureListPreviewButton->insertAction( mLastDisplayExpressionAction, previewAction );
397  mLastDisplayExpressionAction = previewAction;
398 }
399 
400 void QgsDualView::mFeatureList_aboutToChangeEditSelection( bool &ok )
401 {
402  if ( mLayer->isEditable() && !mAttributeForm->save() )
403  ok = false;
404 }
405 
406 void QgsDualView::mFeatureList_currentEditSelectionChanged( const QgsFeature &feat )
407 {
408  if ( !mLayer->isEditable() || mAttributeForm->save() )
409  {
410  mAttributeForm->setFeature( feat );
412  }
413  else
414  {
415  // Couldn't save feature
416  }
417 }
418 
420 {
421  mFeatureList->setCurrentFeatureEdited( false );
422  mFeatureList->setEditSelection( fids );
423 }
424 
426 {
427  return mAttributeForm->save();
428 }
429 
431 {
432  mConditionalFormatWidget->setVisible( !mConditionalFormatWidget->isVisible() );
433  mConditionalFormatWidget->viewRules();
434 }
435 
437 {
438  if ( enabled )
440 
442 }
443 
444 void QgsDualView::toggleSearchMode( bool enabled )
445 {
446  if ( enabled )
447  {
449  mAttributeForm->setMode( QgsAttributeForm::SearchMode );
450  }
451  else
452  {
453  mAttributeForm->setMode( QgsAttributeForm::SingleEditMode );
454  }
455 }
456 
457 void QgsDualView::previewExpressionBuilder()
458 {
459  // Show expression builder
461 
462  QgsExpressionBuilderDialog dlg( mLayer, mFeatureList->displayExpression(), this, QStringLiteral( "generic" ), context );
463  dlg.setWindowTitle( tr( "Expression Based Preview" ) );
464  dlg.setExpressionText( mFeatureList->displayExpression() );
465 
466  if ( dlg.exec() == QDialog::Accepted )
467  {
468  mFeatureList->setDisplayExpression( dlg.expressionText() );
469  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
470  mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
471  }
472 
473  setDisplayExpression( mFeatureList->displayExpression() );
474 }
475 
476 void QgsDualView::previewColumnChanged( QAction *previewAction, const QString &expression )
477 {
478  if ( !mFeatureList->setDisplayExpression( QStringLiteral( "COALESCE( \"%1\", '<NULL>' )" ).arg( expression ) ) )
479  {
480  QMessageBox::warning( this,
481  tr( "Could not set preview column" ),
482  tr( "Could not set column '%1' as preview column.\nParser error:\n%2" )
483  .arg( previewAction->text(), mFeatureList->parserErrorString() )
484  );
485  }
486  else
487  {
488  mFeatureListPreviewButton->setText( previewAction->text() );
489  mFeatureListPreviewButton->setIcon( previewAction->icon() );
490  mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
491  }
492 
493  setDisplayExpression( mFeatureList->displayExpression() );
494 }
495 
497 {
498  return mMasterModel->rowCount();
499 }
500 
502 {
503  return mFilterModel->rowCount();
504 }
505 
507 {
508  QAction *action = qobject_cast<QAction *>( sender() );
509 
510  if ( action && action->data().isValid() && action->data().canConvert<QModelIndex>() )
511  {
512  QModelIndex index = action->data().toModelIndex();
513  QVariant var = masterModel()->data( index, Qt::DisplayRole );
514  QApplication::clipboard()->setText( var.toString() );
515  }
516 }
517 
518 void QgsDualView::hideEvent( QHideEvent *event )
519 {
520  Q_UNUSED( event )
521  saveRecentDisplayExpressions();
522 }
523 
524 void QgsDualView::viewWillShowContextMenu( QMenu *menu, const QModelIndex &atIndex )
525 {
526  if ( !menu )
527  {
528  return;
529  }
530 
531 
532  QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
533 
534  QAction *copyContentAction = new QAction( tr( "Copy cell content" ), this );
535  copyContentAction->setData( QVariant::fromValue<QModelIndex>( sourceIndex ) );
536  menu->addAction( copyContentAction );
537  connect( copyContentAction, &QAction::triggered, this, &QgsDualView::copyCellContent );
538 
539  QgsVectorLayer *vl = mFilterModel->layer();
540  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
541  if ( canvas && vl && vl->geometryType() != QgsWkbTypes::NullGeometry )
542  {
543  menu->addAction( tr( "Zoom to feature" ), this, SLOT( zoomToCurrentFeature() ) );
544  menu->addAction( tr( "Pan to feature" ), this, SLOT( panToCurrentFeature() ) );
545  menu->addAction( tr( "Flash feature" ), this, SLOT( flashCurrentFeature() ) );
546  }
547 
548  //add user-defined actions to context menu
549  QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( "Field" ) );
550  if ( !actions.isEmpty() )
551  {
552  QAction *a = menu->addAction( tr( "Run layer action" ) );
553  a->setEnabled( false );
554 
555  Q_FOREACH ( const QgsAction &action, actions )
556  {
557  if ( !action.runable() )
558  continue;
559 
560  QgsAttributeTableAction *a = new QgsAttributeTableAction( action.name(), this, action.id(), sourceIndex );
561 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
562  menu->addAction( action.name(), a, SLOT( execute() ) );
563 #else
564  menu->addAction( action.name(), a, &QgsAttributeTableAction::execute );
565 #endif
566  }
567  }
568 
569  //add actions from QgsMapLayerActionRegistry to context menu
570  QList<QgsMapLayerAction *> registeredActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer );
571  if ( !registeredActions.isEmpty() )
572  {
573  //add a separator between user defined and standard actions
574  menu->addSeparator();
575 
576  Q_FOREACH ( QgsMapLayerAction *action, registeredActions )
577  {
578  QgsAttributeTableMapLayerAction *a = new QgsAttributeTableMapLayerAction( action->text(), this, action, sourceIndex );
579 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
580  menu->addAction( action->text(), a, SLOT( execut() ) );
581 #else
582  menu->addAction( action->text(), a, &QgsAttributeTableMapLayerAction::execute );
583 #endif
584  }
585  }
586 
587  menu->addSeparator();
588  QgsAttributeTableAction *a = new QgsAttributeTableAction( tr( "Open form" ), this, QString(), sourceIndex );
589 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
590  menu->addAction( tr( "Open form" ), a, SLOT( featureForm() ) );
591 #else
592  menu->addAction( tr( "Open form" ), a, &QgsAttributeTableAction::featureForm );
593 #endif
594 }
595 
596 void QgsDualView::showViewHeaderMenu( QPoint point )
597 {
598  int col = mTableView->columnAt( point.x() );
599 
600  delete mHorizontalHeaderMenu;
601  mHorizontalHeaderMenu = new QMenu( this );
602 
603  QAction *hide = new QAction( tr( "&Hide column" ), mHorizontalHeaderMenu );
604  connect( hide, &QAction::triggered, this, &QgsDualView::hideColumn );
605  hide->setData( col );
606  mHorizontalHeaderMenu->addAction( hide );
607  QAction *setWidth = new QAction( tr( "&Set width..." ), mHorizontalHeaderMenu );
608  connect( setWidth, &QAction::triggered, this, &QgsDualView::resizeColumn );
609  setWidth->setData( col );
610  mHorizontalHeaderMenu->addAction( setWidth );
611  QAction *optimizeWidth = new QAction( tr( "&Autosize" ), mHorizontalHeaderMenu );
612  connect( optimizeWidth, &QAction::triggered, this, &QgsDualView::autosizeColumn );
613  optimizeWidth->setData( col );
614  mHorizontalHeaderMenu->addAction( optimizeWidth );
615 
616  mHorizontalHeaderMenu->addSeparator();
617  QAction *organize = new QAction( tr( "&Organize columns..." ), mHorizontalHeaderMenu );
618  connect( organize, &QAction::triggered, this, &QgsDualView::organizeColumns );
619  mHorizontalHeaderMenu->addAction( organize );
620  QAction *sort = new QAction( tr( "&Sort..." ), mHorizontalHeaderMenu );
621  connect( sort, &QAction::triggered, this, &QgsDualView::modifySort );
622  mHorizontalHeaderMenu->addAction( sort );
623 
624  mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
625 }
626 
627 void QgsDualView::organizeColumns()
628 {
629  if ( !mLayer )
630  {
631  return;
632  }
633 
634  QgsOrganizeTableColumnsDialog dialog( mLayer, this );
635  if ( dialog.exec() == QDialog::Accepted )
636  {
637  QgsAttributeTableConfig config = dialog.config();
638  setAttributeTableConfig( config );
639  }
640 }
641 
642 void QgsDualView::tableColumnResized( int column, int width )
643 {
644  QgsAttributeTableConfig config = mConfig;
645  int sourceCol = config.mapVisibleColumnToIndex( column );
646  if ( sourceCol >= 0 )
647  {
648  config.setColumnWidth( sourceCol, width );
649  setAttributeTableConfig( config );
650  }
651 }
652 
653 void QgsDualView::hideColumn()
654 {
655  QAction *action = qobject_cast<QAction *>( sender() );
656  int col = action->data().toInt();
657  QgsAttributeTableConfig config = mConfig;
658  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
659  if ( sourceCol >= 0 )
660  {
661  config.setColumnHidden( sourceCol, true );
662  setAttributeTableConfig( config );
663  }
664 }
665 
666 void QgsDualView::resizeColumn()
667 {
668  QAction *action = qobject_cast<QAction *>( sender() );
669  int col = action->data().toInt();
670  if ( col < 0 )
671  return;
672 
673  QgsAttributeTableConfig config = mConfig;
674  int sourceCol = config.mapVisibleColumnToIndex( col );
675  if ( sourceCol >= 0 )
676  {
677  bool ok = false;
678  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
679  mTableView->columnWidth( col ),
680  0, 1000, 10, &ok );
681  if ( ok )
682  {
683  config.setColumnWidth( sourceCol, width );
684  setAttributeTableConfig( config );
685  }
686  }
687 }
688 
689 void QgsDualView::autosizeColumn()
690 {
691  QAction *action = qobject_cast<QAction *>( sender() );
692  int col = action->data().toInt();
693  mTableView->resizeColumnToContents( col );
694 }
695 
696 void QgsDualView::modifySort()
697 {
698  if ( !mLayer )
699  return;
700 
701  QgsAttributeTableConfig config = mConfig;
702 
703  QDialog orderByDlg;
704  orderByDlg.setWindowTitle( tr( "Configure Attribute Table Sort Order" ) );
705  QDialogButtonBox *dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
706  QGridLayout *layout = new QGridLayout();
707  connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
708  connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
709  orderByDlg.setLayout( layout );
710 
711  QGroupBox *sortingGroupBox = new QGroupBox();
712  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
713  sortingGroupBox->setCheckable( true );
714  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
715  layout->addWidget( sortingGroupBox );
716  sortingGroupBox->setLayout( new QGridLayout() );
717 
718  QgsExpressionBuilderWidget *expressionBuilder = new QgsExpressionBuilderWidget();
720  expressionBuilder->setExpressionContext( context );
721  expressionBuilder->setLayer( mLayer );
722  expressionBuilder->loadFieldNames();
723  expressionBuilder->loadRecent( QStringLiteral( "generic" ) );
724  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? mLayer->displayExpression() : sortExpression() );
725 
726  sortingGroupBox->layout()->addWidget( expressionBuilder );
727 
728  QCheckBox *cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
729  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
730  sortingGroupBox->layout()->addWidget( cbxSortAscending );
731 
732  layout->addWidget( dialogButtonBox );
733  if ( orderByDlg.exec() )
734  {
735  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
736  if ( sortingGroupBox->isChecked() )
737  {
738  setSortExpression( expressionBuilder->expressionText(), sortOrder );
739  config.setSortExpression( expressionBuilder->expressionText() );
740  config.setSortOrder( sortOrder );
741  }
742  else
743  {
744  setSortExpression( QString(), sortOrder );
745  config.setSortExpression( QString() );
746  }
747 
748  setAttributeTableConfig( config );
749  }
750 }
751 
752 void QgsDualView::zoomToCurrentFeature()
753 {
754  QModelIndex currentIndex = mTableView->currentIndex();
755  if ( !currentIndex.isValid() )
756  {
757  return;
758  }
759 
760  QgsFeatureIds ids;
761  ids.insert( mFilterModel->rowToId( currentIndex ) );
762  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
763  if ( canvas )
764  {
765  canvas->zoomToFeatureIds( mLayer, ids );
766  }
767 }
768 
769 void QgsDualView::panToCurrentFeature()
770 {
771  QModelIndex currentIndex = mTableView->currentIndex();
772  if ( !currentIndex.isValid() )
773  {
774  return;
775  }
776 
777  QgsFeatureIds ids;
778  ids.insert( mFilterModel->rowToId( currentIndex ) );
779  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
780  if ( canvas )
781  {
782  canvas->panToFeatureIds( mLayer, ids );
783  }
784 }
785 
786 void QgsDualView::flashCurrentFeature()
787 {
788  QModelIndex currentIndex = mTableView->currentIndex();
789  if ( !currentIndex.isValid() )
790  {
791  return;
792  }
793 
794  QgsFeatureIds ids;
795  ids.insert( mFilterModel->rowToId( currentIndex ) );
796  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
797  if ( canvas )
798  {
799  canvas->flashFeatureIds( mLayer, ids );
800  }
801 }
802 
803 void QgsDualView::rebuildFullLayerCache()
804 {
805  connect( mLayerCache, &QgsVectorLayerCache::progress, this, &QgsDualView::progress, Qt::UniqueConnection );
806  connect( mLayerCache, &QgsVectorLayerCache::finished, this, &QgsDualView::finished, Qt::UniqueConnection );
807 
808  mLayerCache->setFullCache( true );
809 }
810 
811 void QgsDualView::previewExpressionChanged( const QString &expression )
812 {
813  mLayer->setDisplayExpression( expression );
814 }
815 
816 void QgsDualView::onSortColumnChanged()
817 {
819  cfg.setSortExpression( mFilterModel->sortExpression() );
820  cfg.setSortOrder( mFilterModel->sortOrder() );
822 }
823 
824 void QgsDualView::sortByPreviewExpression()
825 {
826  Qt::SortOrder sortOrder = Qt::AscendingOrder;
827  if ( mFeatureList->displayExpression() == sortExpression() )
828  {
829  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
830  }
831  setSortExpression( mFeatureList->displayExpression(), sortOrder );
832 }
833 
834 void QgsDualView::updateSelectedFeatures()
835 {
836  QgsFeatureRequest r = mMasterModel->request();
838  return; // already requested all features
839 
840  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
841  mMasterModel->setRequest( r );
842  mMasterModel->loadLayer();
843  emit filterChanged();
844 }
845 
846 void QgsDualView::extentChanged()
847 {
848  QgsFeatureRequest r = mMasterModel->request();
849  if ( mMapCanvas && ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) )
850  {
851  QgsRectangle rect = mMapCanvas->mapSettings().mapToLayerCoordinates( mLayer, mMapCanvas->extent() );
852  r.setFilterRect( rect );
853  mMasterModel->setRequest( r );
854  mMasterModel->loadLayer();
855  }
856  emit filterChanged();
857 }
858 
859 void QgsDualView::featureFormAttributeChanged()
860 {
861  mFeatureList->setCurrentFeatureEdited( true );
862 }
863 
865 {
866  mFilterModel->setFilteredFeatures( filteredFeatures );
867 }
868 
870 {
871  mMasterModel->setRequest( request );
872 }
873 
875 {
876  mTableView->setFeatureSelectionManager( featureSelectionManager );
877  mFeatureList->setFeatureSelectionManager( featureSelectionManager );
878 
879  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
880  delete mFeatureSelectionManager;
881 
882  mFeatureSelectionManager = featureSelectionManager;
883 }
884 
886 {
887  mConfig = config;
888  mLayer->setAttributeTableConfig( config );
889  mFilterModel->setAttributeTableConfig( config );
890  mTableView->setAttributeTableConfig( config );
891 }
892 
893 void QgsDualView::setSortExpression( const QString &sortExpression, Qt::SortOrder sortOrder )
894 {
895  if ( sortExpression.isNull() )
896  mFilterModel->sort( -1 );
897  else
898  mFilterModel->sort( sortExpression, sortOrder );
899 
900  mConfig.setSortExpression( sortExpression );
901  mConfig.setSortOrder( sortOrder );
902  setAttributeTableConfig( mConfig );
903 }
904 
906 {
907  return mFilterModel->sortExpression();
908 }
909 
910 void QgsDualView::progress( int i, bool &cancel )
911 {
912  if ( !mProgressDlg )
913  {
914  mProgressDlg = new QProgressDialog( tr( "Loading features..." ), tr( "Abort" ), 0, 0, this );
915  mProgressDlg->setWindowTitle( tr( "Attribute Table" ) );
916  mProgressDlg->setWindowModality( Qt::WindowModal );
917  mProgressDlg->show();
918  }
919 
920  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
921  QCoreApplication::processEvents();
922 
923  cancel = mProgressDlg && mProgressDlg->wasCanceled();
924 }
925 
926 void QgsDualView::finished()
927 {
928  delete mProgressDlg;
929  mProgressDlg = nullptr;
930 }
931 
932 /*
933  * QgsAttributeTableAction
934  */
935 
937 {
938  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
939 }
940 
942 {
943  QgsFeatureIds editedIds;
944  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
945  mDualView->setCurrentEditSelection( editedIds );
946  mDualView->setView( QgsDualView::AttributeEditor );
947 }
948 
949 /*
950  * QgsAttributeTableMapLayerAction
951  */
952 
954 {
955  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
956 }
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:299
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
QgsActionManager * actions()
Get all layer actions defined on this layer.
QgsFeatureId id
Definition: qgsfeature.h:71
QgsFeatureId rowToId(const QModelIndex &row)
Returns the feature id for a given model index.
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
void setFilterMode(QgsAttributeTableFilterModel::FilterMode filterMode)
Set the filter mode.
A rectangle specified with double values.
Definition: qgsrectangle.h:39
void setSortExpression(const QString &sortExpression)
Set the sort expression used for sorting.
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table configuration to control which fields are shown, in which order they are show...
void init(QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request=QgsFeatureRequest(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), bool loadFeatures=true)
Has to be called to initialize the dual view.
Definition: qgsdualview.cpp:63
void setExpressionText(const QString &text)
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
QgsFeatureId idxToFid(const QModelIndex &index) const
QgsAttributeTableConfig config() const
Get the updated configuration.
void willShowContextMenu(QMenu *menu, const QModelIndex &atIndex)
Is emitted, in order to provide a hook to add additional* menu entries to the context menu...
const Flags & flags() const
QString name
Definition: qgsfield.h:56
void setSelectedOnTop(bool selectedOnTop)
Changes the sort order of the features.
QgsAttributeTableModel * masterModel() const
Returns the model which has the information about all features (not only filtered) ...
Definition: qgsdualview.h:162
void filterExpressionSet(const QString &expression, QgsAttributeForm::FilterType type)
Is emitted when a filter expression is set using the view.
void setSortOrder(Qt::SortOrder sortOrder)
Set the sort order.
void setFilterMode(FilterMode filterMode)
Set the filter mode the filter will use.
void toggleSearchMode(bool enabled)
Toggles whether search mode should be enabled in the form.
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
Set the feature selection model.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:55
void invalidated()
The cache has been invalidated and cleared.
void openConditionalStyles()
Multi edit mode, for editing fields of multiple features at once.
QIcon iconForField(int fieldIdx) const
Returns an icon corresponding to a field index, based on the field&#39;s type and source.
Definition: qgsfields.cpp:257
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:544
QString sortExpression() const
Get the expression used for sorting the table and feature list.
This class contains context information for attribute editor widgets.
void setLayer(QgsVectorLayer *layer)
Sets layer in order to get the fields and values.
bool save()
Save all the values from the editors to the layer.
ViewMode
The view modes, in which this widget can present information.
Definition: qgsdualview.h:54
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
void loadRecent(const QString &collection="generic")
Loads the recent expressions from the given collection.
FilterType filterType() const
Return the filter type which is currently set on this request.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
QList< QgsAction > actions(const QString &actionScope=QString()) const
Return a list of actions that are available in the given action scope.
void fieldConditionalStyleChanged(const QString &fieldName)
Handles updating the model when the conditional style for a field changes.
int filteredFeatureCount()
Returns the number of features which are currently visible, according to the filter restrictions...
void columnResized(int column, int width)
Emitted when a column in the view has been resized.
QgsDualView(QWidget *parent=0)
Constructor.
Definition: qgsdualview.cpp:42
void setDisplayExpression(const QString &displayExpression)
Set the preview expression, used to create a human readable preview string.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
Show only visible features (depends on the map canvas)
void setCurrentEditSelection(const QgsFeatureIds &fids)
Set the current edit selection in the AttributeEditor mode.
int mapVisibleColumnToIndex(int visibleColumn) const
Maps a visible column index to its original column index.
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
virtual void hideEvent(QHideEvent *event) override
void setView(ViewMode view)
Change the current view mode.
virtual void setFilteredFeatures(const QgsFeatureIds &ids)
Specify a list of features, which the filter will accept.
virtual QVariant data(const QModelIndex &index, int role) const override
Returns data on the given index.
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table config which should be used to control the appearance of the attribute table...
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
Definition: qgsdualview.h:67
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void setMode(Mode mode)
Sets the current mode of the form.
void setColumnWidth(int column, int width)
Sets the width of a column.
void copyCellContent() const
Copy the content of the selected cell in the clipboard.
void setSortExpression(const QString &sortExpression, Qt::SortOrder sortOrder=Qt::AscendingOrder)
Set the expression used for sorting the table and feature list.
FilterMode filterMode()
The current filterModel.
QgsFields fields() const override
Returns the list of fields of this layer.
void setExtraColumns(int extraColumns)
Empty extra columns to announce from this model.
void setFeature(const QgsFeature &feature)
Update all editors to correspond to a different feature.
FilterMode
The filter mode defines how the rows should be filtered.
void flashFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids, const QColor &startColor=QColor(255, 0, 0, 255), const QColor &endColor=QColor(255, 0, 0, 0), int flashes=3, int duration=500)
Causes a set of features with matching ids from a vector layer to flash within the canvas...
Dialog for organising (hiding and reordering) columns in the attributes table.
Form values are used for searching/filtering the layer.
void aboutToChangeEditSelection(bool &ok)
void setEditorContext(const QgsAttributeEditorContext &context)
Sets the context in which this table is shown.
QgsFeatureRequest & disableFilter()
Disables filter conditions.
void filterExpressionSet(const QString &expression, QgsAttributeForm::FilterType type)
Is emitted when a filter expression is set using the form.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories...
Definition: qgsgui.cpp:44
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, const bool clearAndSelect)
This signal is emitted when selection was changed.
ViewMode view() const
Returns the current view mode.
Utility class that encapsulates an action based on vector attributes.
Definition: qgsaction.h:35
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void progress(int i, bool &cancel)
When filling the cache, this signal gets emitted periodically to notify about the progress and to be ...
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
void panToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Centers canvas extent to feature ids.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void modeChanged(QgsAttributeForm::Mode mode)
Emitted when the form changes mode.
bool runable() const
Checks if the action is runable on the current platform.
Definition: qgsaction.cpp:29
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsFeatureIds filteredFeatures()
Get a list of currently visible feature ids.
Definition: qgsdualview.h:155
void refreshFeature()
reload current feature
void displayExpressionChanged(const QString &expression)
Is emitted, whenever the display expression is successfully changed.
void filterChanged()
Is emitted, whenever the filter changes.
QString name() const
The name of the action. This may be a longer description.
Definition: qgsaction.h:95
void loadFieldNames()
Loads all the field names from the layer.
Show only features which have unsaved changes.
const QgsFeatureRequest & request() const
Get the the feature request.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
Fast access to features using their ID.
QString displayExpression
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context for the widget.
QString sortExpression() const
The expression which is used to sort the attribute table.
This class caches features of a given QgsVectorLayer.
const QgsAttributeEditorContext * parentContext() const
bool saveEditChanges()
saveEditChanges
Show only features whose ids are on the filter list. {.
void progress(int i, bool &cancel)
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
void setRequest(const QgsFeatureRequest &request)
Set the request.
QgsAttributeTableFilterModel::FilterMode filterMode()
Get the filter mode.
Definition: qgsdualview.h:119
void modelChanged()
Model has been changed.
A reusable widget that can be used to build a expression string.
QgsAttributeTableConfig attributeTableConfig() const
Get the attribute table configuration object.
void setSelectedOnTop(bool selectedOnTop)
Toggle the selectedOnTop flag.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:200
void zoomToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Set canvas extent to the bounding box of a set of features.
No filter is applied.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Set feature IDs that should be fetched.
int indexOf(const QString &fieldName) const
Get the field index from the field name.
Definition: qgsfields.cpp:189
void attributeChanged(const QString &attribute, const QVariant &value)
Notifies about changes of attributes.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
void setFullCache(bool fullCache)
This enables or disables full caching.
virtual void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Sort by the given column using the given order.
void setColumnHidden(int column, bool hidden)
Sets whether the specified column should be hidden.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:194
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QgsMapCanvas * mapCanvas() const
Returns the map canvas.
void displayExpressionChanged(const QString &expression)
Is emitted, whenever the display expression is successfully changed.
QgsVectorDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer.
QString expressionText()
Gets the expression string that has been set in the expression area.
void formModeChanged(QgsAttributeForm::Mode mode)
Emitted when the form changes mode.
void setExpressionText(const QString &expression)
Sets the expression string for the widget.
QUuid id() const
Returns a unique id for this action.
Definition: qgsaction.h:105
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
Single edit mode, for editing a single feature.
void setFilteredFeatures(const QgsFeatureIds &filteredFeatures)
Set a list of currently visible features.
This is a container for configuration of the attribute table.
Qt::SortOrder sortOrder() const
Get the sort order.
A QScrollArea subclass with improved scrolling behavior.
Definition: qgsscrollarea.h:41
Geometry is not required. It may still be returned if e.g. required for a filter condition.
void setMultiEditEnabled(bool enabled)
Sets whether multi edit mode is enabled.
Is an interface class to abstract feature selection handling.
void currentEditSelectionChanged(QgsFeature &feat)
Is emitted, whenever the current edit selection has been changed.
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer&#39;s CRS
Represents a vector layer which manages a vector based data sets.
void sortColumnChanged(int column, Qt::SortOrder order)
Is emitted whenever the sort column is changed.
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Definition: qgsgui.cpp:64
void finished()
When filling the cache, this signal gets emitted once the cache is fully initialized.
void setAttributeTableConfig(const QgsAttributeTableConfig &attributeTableConfig)
Set the attribute table configuration object.
void extentsChanged()
Emitted when the extents of the map change.
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else...
A generic dialog for building expression strings.
An action which can run on map layers.
int featureCount()
Returns the number of features on the layer.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Set flags that affect how features will be fetched.
void rulesUpdated(const QString &fieldName)
Emitted when the conditional styling rules are updated.