QGIS API Documentation  3.0.2-Girona (307d082)
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  mPreviewColumnsMenu = new QMenu( this );
52  mActionPreviewColumnsMenu->setMenu( mPreviewColumnsMenu );
53 
54  // Set preview icon
55  mActionExpressionPreview->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) ) );
56 
57  // Connect layer list preview signals
58  connect( mActionExpressionPreview, &QAction::triggered, this, &QgsDualView::previewExpressionBuilder );
59  connect( mFeatureList, &QgsFeatureListView::displayExpressionChanged, this, &QgsDualView::previewExpressionChanged );
60 }
61 
62 void QgsDualView::init( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, const QgsAttributeEditorContext &context, bool loadFeatures )
63 {
64  mMapCanvas = mapCanvas;
65 
66  if ( !layer )
67  return;
68 
69  mLayer = layer;
70 
71  mEditorContext = context;
72 
73  connect( mTableView, &QgsAttributeTableView::willShowContextMenu, this, &QgsDualView::viewWillShowContextMenu );
74  mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
75  connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &QgsDualView::showViewHeaderMenu );
76  connect( mTableView, &QgsAttributeTableView::columnResized, this, &QgsDualView::tableColumnResized );
77  connect( mFeatureList, &QgsFeatureListView::willShowContextMenu, this, &QgsDualView::widgetWillShowContextMenu );
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, mTempAttributeFormFeature, mEditorContext );
88  mTempAttributeFormFeature = QgsFeature();
89  if ( !context.parentContext() )
90  {
91  mAttributeEditorScrollArea = new QgsScrollArea();
92  mAttributeEditorScrollArea->setWidgetResizable( true );
93  mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea );
94  mAttributeEditorScrollArea->setWidget( mAttributeForm );
95  }
96  else
97  {
98  mAttributeEditor->layout()->addWidget( mAttributeForm );
99  }
100 
101  connect( mAttributeForm, &QgsAttributeForm::widgetValueChanged, this, &QgsDualView::featureFormAttributeChanged );
102  connect( mAttributeForm, &QgsAttributeForm::modeChanged, this, &QgsDualView::formModeChanged );
103  connect( mMasterModel, &QgsAttributeTableModel::modelChanged, mAttributeForm, &QgsAttributeForm::refreshFeature );
105  connect( mFilterModel, &QgsAttributeTableFilterModel::sortColumnChanged, this, &QgsDualView::onSortColumnChanged );
106 
107  if ( mFeatureListPreviewButton->defaultAction() )
108  mFeatureList->setDisplayExpression( mDisplayExpression );
109  else
110  columnBoxInit();
111 
112  // This slows down load of the attribute table heaps and uses loads of memory.
113  //mTableView->resizeColumnsToContents();
114 
115  mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) );
116 }
117 
118 void QgsDualView::columnBoxInit()
119 {
120  // load fields
121  QList<QgsField> fields = mLayer->fields().toList();
122 
123  QString defaultField;
124 
125  // default expression: saved value
126  QString displayExpression = mLayer->displayExpression();
127 
128  if ( displayExpression.isEmpty() )
129  {
130  // ... there isn't really much to display
131  displayExpression = QStringLiteral( "'[Please define preview text]'" );
132  }
133 
134  mFeatureListPreviewButton->addAction( mActionExpressionPreview );
135  mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
136 
137  Q_FOREACH ( const QgsField &field, fields )
138  {
139  int fieldIndex = mLayer->fields().lookupField( field.name() );
140  if ( fieldIndex == -1 )
141  continue;
142 
143  QString fieldName = field.name();
144  if ( QgsGui::editorWidgetRegistry()->findBest( mLayer, fieldName ).type() != QLatin1String( "Hidden" ) )
145  {
146  QIcon icon = mLayer->fields().iconForField( fieldIndex );
147  QString text = mLayer->attributeDisplayName( fieldIndex );
148 
149  // Generate action for the preview popup button of the feature list
150  QAction *previewAction = new QAction( icon, text, mFeatureListPreviewButton );
151  connect( previewAction, &QAction::triggered, this, [ = ] { previewColumnChanged( previewAction, fieldName ); } );
152  mPreviewColumnsMenu->addAction( previewAction );
153 
154  if ( text == defaultField )
155  {
156  mFeatureListPreviewButton->setDefaultAction( previewAction );
157  }
158  }
159  }
160 
161  QAction *sortByPreviewExpression = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "sort.svg" ) ), tr( "Sort by preview expression" ), this );
162  connect( sortByPreviewExpression, &QAction::triggered, this, &QgsDualView::sortByPreviewExpression );
163  mFeatureListPreviewButton->addAction( sortByPreviewExpression );
164 
165  QAction *separator = new QAction( mFeatureListPreviewButton );
166  separator->setSeparator( true );
167  mFeatureListPreviewButton->addAction( separator );
168  restoreRecentDisplayExpressions();
169 
170  // If there is no single field found as preview
171  if ( !mFeatureListPreviewButton->defaultAction() )
172  {
173  mFeatureList->setDisplayExpression( displayExpression );
174  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
175  setDisplayExpression( mFeatureList->displayExpression() );
176  }
177  else
178  {
179  mFeatureListPreviewButton->defaultAction()->trigger();
180  }
181 }
182 
184 {
185  setCurrentIndex( view );
186 }
187 
189 {
190  return static_cast< QgsDualView::ViewMode >( currentIndex() );
191 }
192 
194 {
195  // cleanup any existing connections
196  switch ( mFilterModel->filterMode() )
197  {
199  disconnect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
200  break;
201 
205  break;
206 
208  disconnect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
209  break;
210  }
211 
212  QgsFeatureRequest r = mMasterModel->request();
213  bool needsGeometry = filterMode == QgsAttributeTableFilterModel::ShowVisible;
214 
215  bool requiresTableReload = ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) // previous request was subset
216  || ( needsGeometry && r.flags() & QgsFeatureRequest::NoGeometry ) // no geometry for last request
217  || ( mMasterModel->rowCount() == 0 ); // no features
218 
219  if ( !needsGeometry )
221  else
225  r.disableFilter();
226 
227  // setup new connections and filter request parameters
228  switch ( filterMode )
229  {
231  connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
232  if ( mMapCanvas )
233  {
234  QgsRectangle rect = mMapCanvas->mapSettings().mapToLayerCoordinates( mLayer, mMapCanvas->extent() );
235  r.setFilterRect( rect );
236  }
237  break;
238 
242  break;
243 
245  connect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
246  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
247  break;
248  }
249 
250  if ( requiresTableReload )
251  {
252  mMasterModel->setRequest( r );
253  whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry );
254  mMasterModel->loadLayer();
255  }
256 
257  //update filter model
258  mFilterModel->setFilterMode( filterMode );
259  emit filterChanged();
260 }
261 
262 void QgsDualView::setSelectedOnTop( bool selectedOnTop )
263 {
264  mFilterModel->setSelectedOnTop( selectedOnTop );
265 }
266 
267 void QgsDualView::initLayerCache( bool cacheGeometry )
268 {
269  // Initialize the cache
270  QgsSettings settings;
271  int cacheSize = settings.value( QStringLiteral( "qgis/attributeTableRowCache" ), "10000" ).toInt();
272  mLayerCache = new QgsVectorLayerCache( mLayer, cacheSize, this );
273  mLayerCache->setCacheGeometry( cacheGeometry );
274  if ( 0 == cacheSize || 0 == ( QgsVectorDataProvider::SelectAtId & mLayer->dataProvider()->capabilities() ) )
275  {
276  connect( mLayerCache, &QgsVectorLayerCache::invalidated, this, &QgsDualView::rebuildFullLayerCache );
277  rebuildFullLayerCache();
278  }
279 }
280 
281 void QgsDualView::initModels( QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, bool loadFeatures )
282 {
283  delete mFeatureListModel;
284  delete mFilterModel;
285  delete mMasterModel;
286 
287  mMasterModel = new QgsAttributeTableModel( mLayerCache, this );
288  mMasterModel->setRequest( request );
289  mMasterModel->setEditorContext( mEditorContext );
290  mMasterModel->setExtraColumns( 1 ); // Add one extra column which we can "abuse" as an action column
291 
292  connect( mMasterModel, &QgsAttributeTableModel::progress, this, &QgsDualView::progress );
293  connect( mMasterModel, &QgsAttributeTableModel::finished, this, &QgsDualView::finished );
294 
296 
297  if ( loadFeatures )
298  mMasterModel->loadLayer();
299 
300  mFilterModel = new QgsAttributeTableFilterModel( mapCanvas, mMasterModel, mMasterModel );
301 
302  // The following connections to invalidate() are necessary to keep the filter model in sync
303  // see regression https://issues.qgis.org/issues/15974
304  connect( mMasterModel, &QgsAttributeTableModel::rowsRemoved, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
305  connect( mMasterModel, &QgsAttributeTableModel::rowsInserted, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
306 
308 
309  mFeatureListModel = new QgsFeatureListModel( mFilterModel, mFilterModel );
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  {
458  mAttributeForm->setMode( QgsAttributeForm::SearchMode );
459  }
460  else
461  {
462  mAttributeForm->setMode( QgsAttributeForm::SingleEditMode );
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 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
579  menu->addAction( action.name(), a, SLOT( execute() ) );
580 #else
581  menu->addAction( action.name(), a, &QgsAttributeTableAction::execute );
582 #endif
583  }
584  }
585 
586  //add actions from QgsMapLayerActionRegistry to context menu
587  QList<QgsMapLayerAction *> registeredActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer );
588  if ( !registeredActions.isEmpty() )
589  {
590  //add a separator between user defined and standard actions
591  menu->addSeparator();
592 
593  Q_FOREACH ( QgsMapLayerAction *action, registeredActions )
594  {
595  QgsAttributeTableMapLayerAction *a = new QgsAttributeTableMapLayerAction( action->text(), this, action, sourceIndex );
596 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
597  menu->addAction( action->text(), a, SLOT( execut() ) );
598 #else
599  menu->addAction( action->text(), a, &QgsAttributeTableMapLayerAction::execute );
600 #endif
601  }
602  }
603 
604  menu->addSeparator();
605  QgsAttributeTableAction *a = new QgsAttributeTableAction( tr( "Open Form" ), this, QString(), sourceIndex );
606 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
607  menu->addAction( tr( "Open Form" ), a, SLOT( featureForm() ) );
608 #else
609  menu->addAction( tr( "Open Form" ), a, &QgsAttributeTableAction::featureForm );
610 #endif
611 }
612 
613 
614 void QgsDualView::widgetWillShowContextMenu( QgsActionMenu *menu, const QModelIndex &atIndex )
615 {
616  emit showContextMenuExternally( menu, mFilterModel->rowToId( atIndex ) );
617 }
618 
619 
620 void QgsDualView::showViewHeaderMenu( QPoint point )
621 {
622  int col = mTableView->columnAt( point.x() );
623 
624  delete mHorizontalHeaderMenu;
625  mHorizontalHeaderMenu = new QMenu( this );
626 
627  QAction *hide = new QAction( tr( "&Hide Column" ), mHorizontalHeaderMenu );
628  connect( hide, &QAction::triggered, this, &QgsDualView::hideColumn );
629  hide->setData( col );
630  mHorizontalHeaderMenu->addAction( hide );
631  QAction *setWidth = new QAction( tr( "&Set Width…" ), mHorizontalHeaderMenu );
632  connect( setWidth, &QAction::triggered, this, &QgsDualView::resizeColumn );
633  setWidth->setData( col );
634  mHorizontalHeaderMenu->addAction( setWidth );
635  QAction *optimizeWidth = new QAction( tr( "&Autosize" ), mHorizontalHeaderMenu );
636  connect( optimizeWidth, &QAction::triggered, this, &QgsDualView::autosizeColumn );
637  optimizeWidth->setData( col );
638  mHorizontalHeaderMenu->addAction( optimizeWidth );
639 
640  mHorizontalHeaderMenu->addSeparator();
641  QAction *organize = new QAction( tr( "&Organize Columns…" ), mHorizontalHeaderMenu );
642  connect( organize, &QAction::triggered, this, &QgsDualView::organizeColumns );
643  mHorizontalHeaderMenu->addAction( organize );
644  QAction *sort = new QAction( tr( "&Sort…" ), mHorizontalHeaderMenu );
645  connect( sort, &QAction::triggered, this, &QgsDualView::modifySort );
646  mHorizontalHeaderMenu->addAction( sort );
647 
648  mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
649 }
650 
651 void QgsDualView::organizeColumns()
652 {
653  if ( !mLayer )
654  {
655  return;
656  }
657 
658  QgsOrganizeTableColumnsDialog dialog( mLayer, this );
659  if ( dialog.exec() == QDialog::Accepted )
660  {
661  QgsAttributeTableConfig config = dialog.config();
662  setAttributeTableConfig( config );
663  }
664 }
665 
666 void QgsDualView::tableColumnResized( int column, int width )
667 {
668  QgsAttributeTableConfig config = mConfig;
669  int sourceCol = config.mapVisibleColumnToIndex( column );
670  if ( sourceCol >= 0 && config.columnWidth( sourceCol ) != width )
671  {
672  config.setColumnWidth( sourceCol, width );
673  setAttributeTableConfig( config );
674  }
675 }
676 
677 void QgsDualView::hideColumn()
678 {
679  QAction *action = qobject_cast<QAction *>( sender() );
680  int col = action->data().toInt();
681  QgsAttributeTableConfig config = mConfig;
682  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
683  if ( sourceCol >= 0 )
684  {
685  config.setColumnHidden( sourceCol, true );
686  setAttributeTableConfig( config );
687  }
688 }
689 
690 void QgsDualView::resizeColumn()
691 {
692  QAction *action = qobject_cast<QAction *>( sender() );
693  int col = action->data().toInt();
694  if ( col < 0 )
695  return;
696 
697  QgsAttributeTableConfig config = mConfig;
698  int sourceCol = config.mapVisibleColumnToIndex( col );
699  if ( sourceCol >= 0 )
700  {
701  bool ok = false;
702  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
703  mTableView->columnWidth( col ),
704  0, 1000, 10, &ok );
705  if ( ok )
706  {
707  config.setColumnWidth( sourceCol, width );
708  setAttributeTableConfig( config );
709  }
710  }
711 }
712 
713 void QgsDualView::autosizeColumn()
714 {
715  QAction *action = qobject_cast<QAction *>( sender() );
716  int col = action->data().toInt();
717  mTableView->resizeColumnToContents( col );
718 }
719 
720 void QgsDualView::modifySort()
721 {
722  if ( !mLayer )
723  return;
724 
725  QgsAttributeTableConfig config = mConfig;
726 
727  QDialog orderByDlg;
728  orderByDlg.setWindowTitle( tr( "Configure Attribute Table Sort Order" ) );
729  QDialogButtonBox *dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
730  QGridLayout *layout = new QGridLayout();
731  connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
732  connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
733  orderByDlg.setLayout( layout );
734 
735  QGroupBox *sortingGroupBox = new QGroupBox();
736  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
737  sortingGroupBox->setCheckable( true );
738  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
739  layout->addWidget( sortingGroupBox );
740  sortingGroupBox->setLayout( new QGridLayout() );
741 
742  QgsExpressionBuilderWidget *expressionBuilder = new QgsExpressionBuilderWidget();
744  expressionBuilder->setExpressionContext( context );
745  expressionBuilder->setLayer( mLayer );
746  expressionBuilder->loadFieldNames();
747  expressionBuilder->loadRecent( QStringLiteral( "generic" ) );
748  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? mLayer->displayExpression() : sortExpression() );
749 
750  sortingGroupBox->layout()->addWidget( expressionBuilder );
751 
752  QCheckBox *cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
753  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
754  sortingGroupBox->layout()->addWidget( cbxSortAscending );
755 
756  layout->addWidget( dialogButtonBox );
757  if ( orderByDlg.exec() )
758  {
759  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
760  if ( sortingGroupBox->isChecked() )
761  {
762  setSortExpression( expressionBuilder->expressionText(), sortOrder );
763  config.setSortExpression( expressionBuilder->expressionText() );
764  config.setSortOrder( sortOrder );
765  }
766  else
767  {
768  setSortExpression( QString(), sortOrder );
769  config.setSortExpression( QString() );
770  }
771 
772  setAttributeTableConfig( config );
773  }
774 }
775 
776 void QgsDualView::zoomToCurrentFeature()
777 {
778  QModelIndex currentIndex = mTableView->currentIndex();
779  if ( !currentIndex.isValid() )
780  {
781  return;
782  }
783 
784  QgsFeatureIds ids;
785  ids.insert( mFilterModel->rowToId( currentIndex ) );
786  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
787  if ( canvas )
788  {
789  canvas->zoomToFeatureIds( mLayer, ids );
790  }
791 }
792 
793 void QgsDualView::panToCurrentFeature()
794 {
795  QModelIndex currentIndex = mTableView->currentIndex();
796  if ( !currentIndex.isValid() )
797  {
798  return;
799  }
800 
801  QgsFeatureIds ids;
802  ids.insert( mFilterModel->rowToId( currentIndex ) );
803  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
804  if ( canvas )
805  {
806  canvas->panToFeatureIds( mLayer, ids );
807  }
808 }
809 
810 void QgsDualView::flashCurrentFeature()
811 {
812  QModelIndex currentIndex = mTableView->currentIndex();
813  if ( !currentIndex.isValid() )
814  {
815  return;
816  }
817 
818  QgsFeatureIds ids;
819  ids.insert( mFilterModel->rowToId( currentIndex ) );
820  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
821  if ( canvas )
822  {
823  canvas->flashFeatureIds( mLayer, ids );
824  }
825 }
826 
827 void QgsDualView::rebuildFullLayerCache()
828 {
829  connect( mLayerCache, &QgsVectorLayerCache::progress, this, &QgsDualView::progress, Qt::UniqueConnection );
830  connect( mLayerCache, &QgsVectorLayerCache::finished, this, &QgsDualView::finished, Qt::UniqueConnection );
831 
832  mLayerCache->setFullCache( true );
833 }
834 
835 void QgsDualView::previewExpressionChanged( const QString &expression )
836 {
837  mLayer->setDisplayExpression( expression );
838 }
839 
840 void QgsDualView::onSortColumnChanged()
841 {
842  QgsAttributeTableConfig cfg = mLayer->attributeTableConfig();
843  if ( cfg.sortExpression() != mFilterModel->sortExpression() ||
844  cfg.sortOrder() != mFilterModel->sortOrder() )
845  {
846  cfg.setSortExpression( mFilterModel->sortExpression() );
847  cfg.setSortOrder( mFilterModel->sortOrder() );
849  }
850 }
851 
852 void QgsDualView::sortByPreviewExpression()
853 {
854  Qt::SortOrder sortOrder = Qt::AscendingOrder;
855  if ( mFeatureList->displayExpression() == sortExpression() )
856  {
857  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
858  }
859  setSortExpression( mFeatureList->displayExpression(), sortOrder );
860 }
861 
862 void QgsDualView::updateSelectedFeatures()
863 {
864  QgsFeatureRequest r = mMasterModel->request();
866  return; // already requested all features
867 
868  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
869  mMasterModel->setRequest( r );
870  mMasterModel->loadLayer();
871  emit filterChanged();
872 }
873 
874 void QgsDualView::extentChanged()
875 {
876  QgsFeatureRequest r = mMasterModel->request();
877  if ( mMapCanvas && ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) )
878  {
879  QgsRectangle rect = mMapCanvas->mapSettings().mapToLayerCoordinates( mLayer, mMapCanvas->extent() );
880  r.setFilterRect( rect );
881  mMasterModel->setRequest( r );
882  mMasterModel->loadLayer();
883  }
884  emit filterChanged();
885 }
886 
887 void QgsDualView::featureFormAttributeChanged( const QString &attribute, const QVariant &value, bool attributeChanged )
888 {
889  Q_UNUSED( attribute );
890  Q_UNUSED( value );
891  if ( attributeChanged )
892  mFeatureList->setCurrentFeatureEdited( true );
893 }
894 
896 {
897  mFilterModel->setFilteredFeatures( filteredFeatures );
898 }
899 
901 {
902  mMasterModel->setRequest( request );
903 }
904 
906 {
907  mTableView->setFeatureSelectionManager( featureSelectionManager );
908  mFeatureList->setFeatureSelectionManager( featureSelectionManager );
909 
910  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
911  delete mFeatureSelectionManager;
912 
913  mFeatureSelectionManager = featureSelectionManager;
914 }
915 
917 {
918  mConfig = config;
919  mConfig.update( mLayer->fields() );
920  mLayer->setAttributeTableConfig( mConfig );
921  mFilterModel->setAttributeTableConfig( mConfig );
922  mTableView->setAttributeTableConfig( mConfig );
923 }
924 
925 void QgsDualView::setSortExpression( const QString &sortExpression, Qt::SortOrder sortOrder )
926 {
927  if ( sortExpression.isNull() )
928  mFilterModel->sort( -1 );
929  else
930  mFilterModel->sort( sortExpression, sortOrder );
931 
932  mConfig.setSortExpression( sortExpression );
933  mConfig.setSortOrder( sortOrder );
934  setAttributeTableConfig( mConfig );
935 }
936 
938 {
939  return mFilterModel->sortExpression();
940 }
941 
942 void QgsDualView::progress( int i, bool &cancel )
943 {
944  if ( !mProgressDlg )
945  {
946  mProgressDlg = new QProgressDialog( tr( "Loading features…" ), tr( "Abort" ), 0, 0, this );
947  mProgressDlg->setWindowTitle( tr( "Attribute Table" ) );
948  mProgressDlg->setWindowModality( Qt::WindowModal );
949  mProgressDlg->show();
950  }
951 
952  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
953  QCoreApplication::processEvents();
954 
955  cancel = mProgressDlg && mProgressDlg->wasCanceled();
956 }
957 
958 void QgsDualView::finished()
959 {
960  delete mProgressDlg;
961  mProgressDlg = nullptr;
962 }
963 
964 /*
965  * QgsAttributeTableAction
966  */
967 
969 {
970  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
971 }
972 
974 {
975  QgsFeatureIds editedIds;
976  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
977  mDualView->setCurrentEditSelection( editedIds );
978  mDualView->setView( QgsDualView::AttributeEditor );
979 }
980 
981 /*
982  * QgsAttributeTableMapLayerAction
983  */
984 
986 {
987  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
988 }
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
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 update(const QgsFields &fields)
Update the configuration with the given fields.
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:62
void setExpressionText(const QString &text)
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:57
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:57
void invalidated()
The cache has been invalidated and cleared.
void openConditionalStyles()
Multi edit mode, for editing fields of multiple features at once.
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 isEnabledOnlyWhenEditable() const
Return 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:54
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
Return 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.
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.
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
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:42
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
Definition: qgsdualview.h:67
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.
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)
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:46
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:124
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.
void cancelProgress()
Cancel the progress dialog (if any)
void widgetValueChanged(const QString &attribute, const QVariant &value, bool attributeChanged)
Notifies about changes of attributes.
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.
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:224
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 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.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
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.
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:134
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.
QString sortExpression() const
Get 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:66
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.
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.
void showContextMenuExternally(QgsActionMenu *menu, const QgsFeatureId fid)
Emitted when selecting context menu on the feature list to create the context menu individually...