QGIS API Documentation  3.6.0-Noosa (5873452)
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"
34 
35 #include <QClipboard>
36 #include <QDialog>
37 #include <QMenu>
38 #include <QMessageBox>
39 #include <QProgressDialog>
40 #include <QGroupBox>
41 #include <QInputDialog>
42 
43 QgsDualView::QgsDualView( QWidget *parent )
44  : QStackedWidget( parent )
45 {
46  setupUi( this );
47  connect( mFeatureList, &QgsFeatureListView::aboutToChangeEditSelection, this, &QgsDualView::mFeatureList_aboutToChangeEditSelection );
48  connect( mFeatureList, &QgsFeatureListView::currentEditSelectionChanged, this, &QgsDualView::mFeatureList_currentEditSelectionChanged );
49 
50  mConditionalFormatWidget->hide();
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  if ( !layer )
66  return;
67 
68  mLayer = layer;
69 
70  mEditorContext = context;
71 
72  connect( mTableView, &QgsAttributeTableView::willShowContextMenu, this, &QgsDualView::viewWillShowContextMenu );
73  mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
74  connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &QgsDualView::showViewHeaderMenu );
75  connect( mTableView, &QgsAttributeTableView::columnResized, this, &QgsDualView::tableColumnResized );
76  connect( mFeatureList, &QgsFeatureListView::willShowContextMenu, this, &QgsDualView::widgetWillShowContextMenu );
77 
78  initLayerCache( !( request.flags() & QgsFeatureRequest::NoGeometry ) || !request.filterRect().isNull() );
79  initModels( mapCanvas, request, loadFeatures );
80 
81  mConditionalFormatWidget->setLayer( mLayer );
82 
83  mTableView->setModel( mFilterModel );
84  mFeatureList->setModel( mFeatureListModel );
85  delete mAttributeForm;
86  mAttributeForm = new QgsAttributeForm( mLayer, mTempAttributeFormFeature, mEditorContext );
87  mTempAttributeFormFeature = QgsFeature();
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::widgetValueChanged, 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( mFilterModel->mapCanvas(), &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( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
231  if ( mFilterModel->mapCanvas() )
232  {
233  QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->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  mFeatureListModel->setSortByDisplayExpression( true );
310 }
311 
312 void QgsDualView::restoreRecentDisplayExpressions()
313 {
314  const QVariantList previewExpressions = mLayer->customProperty( QStringLiteral( "dualview/previewExpressions" ) ).toList();
315 
316  for ( const QVariant &previewExpression : previewExpressions )
317  insertRecentlyUsedDisplayExpression( previewExpression.toString() );
318 }
319 
320 void QgsDualView::saveRecentDisplayExpressions() const
321 {
322  if ( ! mLayer )
323  {
324  return;
325  }
326  QList<QAction *> actions = mFeatureListPreviewButton->actions();
327 
328  // Remove existing same action
329  int index = actions.indexOf( mLastDisplayExpressionAction );
330  if ( index != -1 )
331  {
332  QVariantList previewExpressions;
333  for ( ; index < actions.length(); ++index )
334  {
335  QAction *action = actions.at( index );
336  previewExpressions << action->property( "previewExpression" );
337  }
338 
339  mLayer->setCustomProperty( QStringLiteral( "dualview/previewExpressions" ), previewExpressions );
340  }
341 }
342 
343 void QgsDualView::setDisplayExpression( const QString &expression )
344 {
345  mDisplayExpression = expression;
346  insertRecentlyUsedDisplayExpression( expression );
347 }
348 
349 void QgsDualView::insertRecentlyUsedDisplayExpression( const QString &expression )
350 {
351  QList<QAction *> actions = mFeatureListPreviewButton->actions();
352 
353  // Remove existing same action
354  int index = actions.indexOf( mLastDisplayExpressionAction );
355  if ( index != -1 )
356  {
357  for ( int i = 0; index + i < actions.length(); ++i )
358  {
359  QAction *action = actions.at( index );
360  if ( action->text() == expression || i >= 9 )
361  {
362  if ( action == mLastDisplayExpressionAction )
363  mLastDisplayExpressionAction = nullptr;
364  mFeatureListPreviewButton->removeAction( action );
365  }
366  else
367  {
368  if ( !mLastDisplayExpressionAction )
369  mLastDisplayExpressionAction = action;
370  }
371  }
372  }
373 
374  QString name = expression;
375  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) );
376  if ( expression.startsWith( QLatin1String( "COALESCE( \"" ) ) && expression.endsWith( QLatin1String( ", '<NULL>' )" ) ) )
377  {
378  name = expression.mid( 11, expression.length() - 24 ); // Numbers calculated from the COALESCE / <NULL> parts
379 
380  int fieldIndex = mLayer->fields().indexOf( name );
381  if ( fieldIndex != -1 )
382  {
383  name = mLayer->attributeDisplayName( fieldIndex );
384  icon = mLayer->fields().iconForField( fieldIndex );
385  }
386  else
387  {
388  name = expression;
389  }
390  }
391 
392  QAction *previewAction = new QAction( icon, name, mFeatureListPreviewButton );
393  previewAction->setProperty( "previewExpression", expression );
394  connect( previewAction, &QAction::triggered, this, [expression, this]( bool )
395  {
396  setDisplayExpression( expression );
397  mFeatureListPreviewButton->setText( expression );
398  }
399  );
400 
401  mFeatureListPreviewButton->insertAction( mLastDisplayExpressionAction, previewAction );
402  mLastDisplayExpressionAction = previewAction;
403 }
404 
405 void QgsDualView::mFeatureList_aboutToChangeEditSelection( bool &ok )
406 {
407  if ( mLayer->isEditable() && !mAttributeForm->save() )
408  ok = false;
409 }
410 
411 void QgsDualView::mFeatureList_currentEditSelectionChanged( const QgsFeature &feat )
412 {
413  if ( !mAttributeForm )
414  {
415  mTempAttributeFormFeature = feat;
416  }
417  else if ( !mLayer->isEditable() || mAttributeForm->save() )
418  {
419  mAttributeForm->setFeature( feat );
421  }
422  else
423  {
424  // Couldn't save feature
425  }
426 }
427 
429 {
430  mFeatureList->setCurrentFeatureEdited( false );
431  mFeatureList->setEditSelection( fids );
432 }
433 
435 {
436  return mAttributeForm->save();
437 }
438 
440 {
441  mConditionalFormatWidget->setVisible( !mConditionalFormatWidget->isVisible() );
442  mConditionalFormatWidget->viewRules();
443 }
444 
446 {
447  if ( enabled )
449 
451 }
452 
453 void QgsDualView::toggleSearchMode( bool enabled )
454 {
455  if ( enabled )
456  {
459  }
460  else
461  {
463  }
464 }
465 
466 void QgsDualView::previewExpressionBuilder()
467 {
468  // Show expression builder
470 
471  QgsExpressionBuilderDialog dlg( mLayer, mFeatureList->displayExpression(), this, QStringLiteral( "generic" ), context );
472  dlg.setWindowTitle( tr( "Expression Based Preview" ) );
473  dlg.setExpressionText( mFeatureList->displayExpression() );
474 
475  if ( dlg.exec() == QDialog::Accepted )
476  {
477  mFeatureList->setDisplayExpression( dlg.expressionText() );
478  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
479  mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
480  }
481 
482  setDisplayExpression( mFeatureList->displayExpression() );
483 }
484 
485 void QgsDualView::previewColumnChanged( QAction *previewAction, const QString &expression )
486 {
487  if ( !mFeatureList->setDisplayExpression( QStringLiteral( "COALESCE( \"%1\", '<NULL>' )" ).arg( expression ) ) )
488  {
489  QMessageBox::warning( this,
490  tr( "Column Preview" ),
491  tr( "Could not set column '%1' as preview column.\nParser error:\n%2" )
492  .arg( previewAction->text(), mFeatureList->parserErrorString() )
493  );
494  }
495  else
496  {
497  mFeatureListPreviewButton->setText( previewAction->text() );
498  mFeatureListPreviewButton->setIcon( previewAction->icon() );
499  mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
500  }
501 
502  setDisplayExpression( mFeatureList->displayExpression() );
503 }
504 
506 {
507  return mMasterModel->rowCount();
508 }
509 
511 {
512  return mFilterModel->rowCount();
513 }
514 
516 {
517  QAction *action = qobject_cast<QAction *>( sender() );
518 
519  if ( action && action->data().isValid() && action->data().canConvert<QModelIndex>() )
520  {
521  QModelIndex index = action->data().toModelIndex();
522  QVariant var = masterModel()->data( index, Qt::DisplayRole );
523  QApplication::clipboard()->setText( var.toString() );
524  }
525 }
526 
528 {
529  if ( mProgressDlg )
530  mProgressDlg->cancel();
531 }
532 
533 void QgsDualView::hideEvent( QHideEvent *event )
534 {
535  Q_UNUSED( event )
536  saveRecentDisplayExpressions();
537 }
538 
539 void QgsDualView::viewWillShowContextMenu( QMenu *menu, const QModelIndex &atIndex )
540 {
541  if ( !menu )
542  {
543  return;
544  }
545 
546  QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
547 
548  QAction *copyContentAction = new QAction( tr( "Copy Cell Content" ), this );
549  copyContentAction->setData( QVariant::fromValue<QModelIndex>( sourceIndex ) );
550  menu->addAction( copyContentAction );
551  connect( copyContentAction, &QAction::triggered, this, &QgsDualView::copyCellContent );
552 
553  QgsVectorLayer *vl = mFilterModel->layer();
554  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
555  if ( canvas && vl && vl->geometryType() != QgsWkbTypes::NullGeometry )
556  {
557  menu->addAction( tr( "Zoom to Feature" ), this, SLOT( zoomToCurrentFeature() ) );
558  menu->addAction( tr( "Pan to Feature" ), this, SLOT( panToCurrentFeature() ) );
559  menu->addAction( tr( "Flash Feature" ), this, SLOT( flashCurrentFeature() ) );
560  }
561 
562  //add user-defined actions to context menu
563  QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( "Field" ) );
564  if ( !actions.isEmpty() )
565  {
566  QAction *a = menu->addAction( tr( "Run Layer Action" ) );
567  a->setEnabled( false );
568 
569  Q_FOREACH ( const QgsAction &action, actions )
570  {
571  if ( !action.runable() )
572  continue;
573 
574  if ( vl && !vl->isEditable() && action.isEnabledOnlyWhenEditable() )
575  continue;
576 
577  QgsAttributeTableAction *a = new QgsAttributeTableAction( action.name(), this, action.id(), sourceIndex );
578  menu->addAction( action.name(), a, &QgsAttributeTableAction::execute );
579  }
580  }
581 
582  //add actions from QgsMapLayerActionRegistry to context menu
583  QList<QgsMapLayerAction *> registeredActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer );
584  if ( !registeredActions.isEmpty() )
585  {
586  //add a separator between user defined and standard actions
587  menu->addSeparator();
588 
589  Q_FOREACH ( QgsMapLayerAction *action, registeredActions )
590  {
591  QgsAttributeTableMapLayerAction *a = new QgsAttributeTableMapLayerAction( action->text(), this, action, sourceIndex );
592  menu->addAction( action->text(), a, &QgsAttributeTableMapLayerAction::execute );
593  }
594  }
595 
596  menu->addSeparator();
597  QgsAttributeTableAction *a = new QgsAttributeTableAction( tr( "Open Form" ), this, QString(), sourceIndex );
598  menu->addAction( tr( "Open Form" ), a, &QgsAttributeTableAction::featureForm );
599 }
600 
601 
602 void QgsDualView::widgetWillShowContextMenu( QgsActionMenu *menu, const QModelIndex &atIndex )
603 {
604  emit showContextMenuExternally( menu, mFilterModel->rowToId( atIndex ) );
605 }
606 
607 
608 void QgsDualView::showViewHeaderMenu( QPoint point )
609 {
610  int col = mTableView->columnAt( point.x() );
611 
612  delete mHorizontalHeaderMenu;
613  mHorizontalHeaderMenu = new QMenu( this );
614 
615  QAction *hide = new QAction( tr( "&Hide Column" ), mHorizontalHeaderMenu );
616  connect( hide, &QAction::triggered, this, &QgsDualView::hideColumn );
617  hide->setData( col );
618  mHorizontalHeaderMenu->addAction( hide );
619  QAction *setWidth = new QAction( tr( "&Set Width…" ), mHorizontalHeaderMenu );
620  connect( setWidth, &QAction::triggered, this, &QgsDualView::resizeColumn );
621  setWidth->setData( col );
622  mHorizontalHeaderMenu->addAction( setWidth );
623  QAction *optimizeWidth = new QAction( tr( "&Autosize" ), mHorizontalHeaderMenu );
624  connect( optimizeWidth, &QAction::triggered, this, &QgsDualView::autosizeColumn );
625  optimizeWidth->setData( col );
626  mHorizontalHeaderMenu->addAction( optimizeWidth );
627 
628  mHorizontalHeaderMenu->addSeparator();
629  QAction *organize = new QAction( tr( "&Organize Columns…" ), mHorizontalHeaderMenu );
630  connect( organize, &QAction::triggered, this, &QgsDualView::organizeColumns );
631  mHorizontalHeaderMenu->addAction( organize );
632  QAction *sort = new QAction( tr( "&Sort…" ), mHorizontalHeaderMenu );
633  connect( sort, &QAction::triggered, this, &QgsDualView::modifySort );
634  mHorizontalHeaderMenu->addAction( sort );
635 
636  mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
637 }
638 
639 void QgsDualView::organizeColumns()
640 {
641  if ( !mLayer )
642  {
643  return;
644  }
645 
646  QgsOrganizeTableColumnsDialog dialog( mLayer, attributeTableConfig(), this );
647  if ( dialog.exec() == QDialog::Accepted )
648  {
649  QgsAttributeTableConfig config = dialog.config();
650  setAttributeTableConfig( config );
651  }
652 }
653 
654 void QgsDualView::tableColumnResized( int column, int width )
655 {
656  QgsAttributeTableConfig config = mConfig;
657  int sourceCol = config.mapVisibleColumnToIndex( column );
658  if ( sourceCol >= 0 && config.columnWidth( sourceCol ) != width )
659  {
660  config.setColumnWidth( sourceCol, width );
661  setAttributeTableConfig( config );
662  }
663 }
664 
665 void QgsDualView::hideColumn()
666 {
667  QAction *action = qobject_cast<QAction *>( sender() );
668  int col = action->data().toInt();
669  QgsAttributeTableConfig config = mConfig;
670  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
671  if ( sourceCol >= 0 )
672  {
673  config.setColumnHidden( sourceCol, true );
674  setAttributeTableConfig( config );
675  }
676 }
677 
678 void QgsDualView::resizeColumn()
679 {
680  QAction *action = qobject_cast<QAction *>( sender() );
681  int col = action->data().toInt();
682  if ( col < 0 )
683  return;
684 
685  QgsAttributeTableConfig config = mConfig;
686  int sourceCol = config.mapVisibleColumnToIndex( col );
687  if ( sourceCol >= 0 )
688  {
689  bool ok = false;
690  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
691  mTableView->columnWidth( col ),
692  0, 1000, 10, &ok );
693  if ( ok )
694  {
695  config.setColumnWidth( sourceCol, width );
696  setAttributeTableConfig( config );
697  }
698  }
699 }
700 
701 void QgsDualView::autosizeColumn()
702 {
703  QAction *action = qobject_cast<QAction *>( sender() );
704  int col = action->data().toInt();
705  mTableView->resizeColumnToContents( col );
706 }
707 
708 void QgsDualView::modifySort()
709 {
710  if ( !mLayer )
711  return;
712 
713  QgsAttributeTableConfig config = mConfig;
714 
715  QDialog orderByDlg;
716  orderByDlg.setWindowTitle( tr( "Configure Attribute Table Sort Order" ) );
717  QDialogButtonBox *dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
718  QGridLayout *layout = new QGridLayout();
719  connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
720  connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
721  orderByDlg.setLayout( layout );
722 
723  QGroupBox *sortingGroupBox = new QGroupBox();
724  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
725  sortingGroupBox->setCheckable( true );
726  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
727  layout->addWidget( sortingGroupBox );
728  sortingGroupBox->setLayout( new QGridLayout() );
729 
730  QgsExpressionBuilderWidget *expressionBuilder = new QgsExpressionBuilderWidget();
732  expressionBuilder->setExpressionContext( context );
733  expressionBuilder->setLayer( mLayer );
734  expressionBuilder->loadFieldNames();
735  expressionBuilder->loadRecent( QStringLiteral( "generic" ) );
736  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? mLayer->displayExpression() : sortExpression() );
737 
738  sortingGroupBox->layout()->addWidget( expressionBuilder );
739 
740  QCheckBox *cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
741  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
742  sortingGroupBox->layout()->addWidget( cbxSortAscending );
743 
744  layout->addWidget( dialogButtonBox );
745  if ( orderByDlg.exec() )
746  {
747  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
748  if ( sortingGroupBox->isChecked() )
749  {
750  setSortExpression( expressionBuilder->expressionText(), sortOrder );
751  config.setSortExpression( expressionBuilder->expressionText() );
752  config.setSortOrder( sortOrder );
753  }
754  else
755  {
756  setSortExpression( QString(), sortOrder );
757  config.setSortExpression( QString() );
758  }
759 
760  setAttributeTableConfig( config );
761  }
762 }
763 
764 void QgsDualView::zoomToCurrentFeature()
765 {
766  QModelIndex currentIndex = mTableView->currentIndex();
767  if ( !currentIndex.isValid() )
768  {
769  return;
770  }
771 
772  QgsFeatureIds ids;
773  ids.insert( mFilterModel->rowToId( currentIndex ) );
774  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
775  if ( canvas )
776  {
777  canvas->zoomToFeatureIds( mLayer, ids );
778  }
779 }
780 
781 void QgsDualView::panToCurrentFeature()
782 {
783  QModelIndex currentIndex = mTableView->currentIndex();
784  if ( !currentIndex.isValid() )
785  {
786  return;
787  }
788 
789  QgsFeatureIds ids;
790  ids.insert( mFilterModel->rowToId( currentIndex ) );
791  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
792  if ( canvas )
793  {
794  canvas->panToFeatureIds( mLayer, ids );
795  }
796 }
797 
798 void QgsDualView::flashCurrentFeature()
799 {
800  QModelIndex currentIndex = mTableView->currentIndex();
801  if ( !currentIndex.isValid() )
802  {
803  return;
804  }
805 
806  QgsFeatureIds ids;
807  ids.insert( mFilterModel->rowToId( currentIndex ) );
808  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
809  if ( canvas )
810  {
811  canvas->flashFeatureIds( mLayer, ids );
812  }
813 }
814 
815 void QgsDualView::rebuildFullLayerCache()
816 {
817  connect( mLayerCache, &QgsVectorLayerCache::progress, this, &QgsDualView::progress, Qt::UniqueConnection );
818  connect( mLayerCache, &QgsVectorLayerCache::finished, this, &QgsDualView::finished, Qt::UniqueConnection );
819 
820  mLayerCache->setFullCache( true );
821 }
822 
823 void QgsDualView::previewExpressionChanged( const QString &expression )
824 {
825  mLayer->setDisplayExpression( expression );
826 }
827 
828 void QgsDualView::onSortColumnChanged()
829 {
831  if ( cfg.sortExpression() != mFilterModel->sortExpression() ||
832  cfg.sortOrder() != mFilterModel->sortOrder() )
833  {
834  cfg.setSortExpression( mFilterModel->sortExpression() );
835  cfg.setSortOrder( mFilterModel->sortOrder() );
837  }
838 }
839 
840 void QgsDualView::sortByPreviewExpression()
841 {
842  Qt::SortOrder sortOrder = Qt::AscendingOrder;
843  if ( mFeatureList->displayExpression() == sortExpression() )
844  {
845  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
846  }
847  setSortExpression( mFeatureList->displayExpression(), sortOrder );
848 }
849 
850 void QgsDualView::updateSelectedFeatures()
851 {
852  QgsFeatureRequest r = mMasterModel->request();
854  return; // already requested all features
855 
856  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
857  mMasterModel->setRequest( r );
858  mMasterModel->loadLayer();
859  emit filterChanged();
860 }
861 
862 void QgsDualView::extentChanged()
863 {
864  QgsFeatureRequest r = mMasterModel->request();
865  if ( mFilterModel->mapCanvas() && ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) )
866  {
867  QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
868  r.setFilterRect( rect );
869  mMasterModel->setRequest( r );
870  mMasterModel->loadLayer();
871  }
872  emit filterChanged();
873 }
874 
875 void QgsDualView::featureFormAttributeChanged( const QString &attribute, const QVariant &value, bool attributeChanged )
876 {
877  Q_UNUSED( attribute );
878  Q_UNUSED( value );
879  if ( attributeChanged )
880  mFeatureList->setCurrentFeatureEdited( true );
881 }
882 
884 {
885  mFilterModel->setFilteredFeatures( filteredFeatures );
886 }
887 
889 {
890  mMasterModel->setRequest( request );
891 }
892 
894 {
895  mTableView->setFeatureSelectionManager( featureSelectionManager );
896  mFeatureList->setFeatureSelectionManager( featureSelectionManager );
897 
898  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
899  delete mFeatureSelectionManager;
900 
901  mFeatureSelectionManager = featureSelectionManager;
902 }
903 
905 {
906  mConfig = config;
907  mConfig.update( mLayer->fields() );
908  mLayer->setAttributeTableConfig( mConfig );
909  mFilterModel->setAttributeTableConfig( mConfig );
910  mTableView->setAttributeTableConfig( mConfig );
911 }
912 
913 void QgsDualView::setSortExpression( const QString &sortExpression, Qt::SortOrder sortOrder )
914 {
915  if ( sortExpression.isNull() )
916  mFilterModel->sort( -1 );
917  else
918  mFilterModel->sort( sortExpression, sortOrder );
919 
920  mConfig.setSortExpression( sortExpression );
921  mConfig.setSortOrder( sortOrder );
922  setAttributeTableConfig( mConfig );
923 }
924 
926 {
927  return mFilterModel->sortExpression();
928 }
929 
931 {
932  return mConfig;
933 }
934 
935 void QgsDualView::progress( int i, bool &cancel )
936 {
937  if ( !mProgressDlg )
938  {
939  mProgressDlg = new QProgressDialog( tr( "Loading features…" ), tr( "Abort" ), 0, 0, this );
940  mProgressDlg->setWindowTitle( tr( "Attribute Table" ) );
941  mProgressDlg->setWindowModality( Qt::WindowModal );
942  mProgressDlg->show();
943  }
944 
945  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
946  QCoreApplication::processEvents();
947 
948  cancel = mProgressDlg && mProgressDlg->wasCanceled();
949 }
950 
951 void QgsDualView::finished()
952 {
953  delete mProgressDlg;
954  mProgressDlg = nullptr;
955 }
956 
957 /*
958  * QgsAttributeTableAction
959  */
960 
962 {
963  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
964 }
965 
967 {
968  QgsFeatureIds editedIds;
969  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
970  mDualView->setCurrentEditSelection( editedIds );
971  mDualView->setView( QgsDualView::AttributeEditor );
972 }
973 
974 /*
975  * QgsAttributeTableMapLayerAction
976  */
977 
979 {
980  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
981 }
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
QgsFeatureId id
Definition: qgsfeature.h:64
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:41
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 update(const QgsFields &fields)
Update the configuration with the given fields.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
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)
QgsFeatureId idxToFid(const QModelIndex &index) const
Returns the feature ID corresponding to an index from the model.
QgsAttributeTableConfig config() const
Gets 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:58
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:161
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:58
void invalidated()
The cache has been invalidated and cleared.
void openConditionalStyles()
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QString sortExpression() const
Gets 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 isEnabledOnlyWhenEditable() const
Returns whether only enabled in editable mode.
Definition: qgsaction.h:173
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:53
void willShowContextMenu(QgsActionMenu *menu, const QModelIndex &atIndex)
Is emitted, when the context menu is created to add the specific actions to it.
void loadRecent(const QString &collection="generic")
Loads the recent expressions from the given collection.
FilterType filterType() const
Returns the filter type which is currently set on this request.
int columnWidth(int column) const
Returns the width of a column, or -1 if column should use default width.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
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.
Multi edit mode, for editing fields of multiple features at once.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
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.
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:73
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.
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...
QgsDualView(QWidget *parent=nullptr)
Constructor.
Definition: qgsdualview.cpp:43
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
Definition: qgsdualview.h:66
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
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.
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.
void aboutToChangeEditSelection(bool &ok)
This class is a menu that is populated automatically with the actions defined for a given layer...
Definition: qgsactionmenu.h:38
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:59
ViewMode view() const
Returns the current view mode.
QgsAttributeTableConfig attributeTableConfig() const
The config used for the attribute table.
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)...
bool runable() const
Checks if the action is runable on the current platform.
Definition: qgsaction.cpp:30
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsFeatureIds filteredFeatures()
Gets a list of currently visible feature ids.
Definition: qgsdualview.h:154
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:124
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
This signal is emitted when selection was changed.
void loadFieldNames()
Loads all the field names from the layer.
Show only features which have unsaved changes.
const QgsFeatureRequest & request() const
Gets 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.
void cancelProgress()
Cancel the progress dialog (if any)
void widgetValueChanged(const QString &attribute, const QVariant &value, bool attributeChanged)
Notifies about changes of attributes.
void setMode(QgsAttributeEditorContext::Mode mode)
Sets the current mode of the form.
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
Gets access to properties used for map rendering.
void setRequest(const QgsFeatureRequest &request)
Set the request.
QgsAttributeTableFilterModel::FilterMode filterMode()
Gets the filter mode.
Definition: qgsdualview.h:118
void modelChanged()
Model has been changed.
A reusable widget that can be used to build a expression string.
void setSelectedOnTop(bool selectedOnTop)
Toggle the selectedOnTop flag.
void showContextMenuExternally(QgsActionMenu *menu, QgsFeatureId fid)
Emitted when selecting context menu on the feature list to create the context menu individually...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:212
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)
Sets feature IDs that should be fetched.
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.
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.
Single edit mode, for editing a single feature.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:436
QgsMapCanvas * mapCanvas() const
Returns the map canvas.
void displayExpressionChanged(const QString &expression)
Is emitted, whenever the display expression is successfully changed.
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 setExpressionText(const QString &expression)
Sets the expression string for the widget.
QUuid id() const
Returns a unique id for this action.
Definition: qgsaction.h:134
void setSortByDisplayExpression(bool sortByDisplayExpression)
Sort this model by its display expression.
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
Gets the sort order.
Form values are used for searching/filtering the layer.
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.
QString sortExpression() const
Gets the expression used for sorting.
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:79
void finished()
When filling the cache, this signal gets emitted once the cache is fully initialized.
void extentsChanged()
Emitted when the extents of the map change.
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.
void formModeChanged(QgsAttributeEditorContext::Mode mode)
Emitted when the form changes mode.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
void rulesUpdated(const QString &fieldName)
Emitted when the conditional styling rules are updated.
void modeChanged(QgsAttributeEditorContext::Mode mode)
Emitted when the form changes mode.