QGIS API Documentation  3.2.0-Bonn (bc43194)
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  if ( !layer )
65  return;
66 
67  mLayer = layer;
68 
69  mEditorContext = context;
70 
71  connect( mTableView, &QgsAttributeTableView::willShowContextMenu, this, &QgsDualView::viewWillShowContextMenu );
72  mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
73  connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &QgsDualView::showViewHeaderMenu );
74  connect( mTableView, &QgsAttributeTableView::columnResized, this, &QgsDualView::tableColumnResized );
75  connect( mFeatureList, &QgsFeatureListView::willShowContextMenu, this, &QgsDualView::widgetWillShowContextMenu );
76 
77  initLayerCache( !( request.flags() & QgsFeatureRequest::NoGeometry ) || !request.filterRect().isNull() );
78  initModels( mapCanvas, request, loadFeatures );
79 
80  mConditionalFormatWidget->setLayer( mLayer );
81 
82  mTableView->setModel( mFilterModel );
83  mFeatureList->setModel( mFeatureListModel );
84  delete mAttributeForm;
85  mAttributeForm = new QgsAttributeForm( mLayer, mTempAttributeFormFeature, mEditorContext );
86  mTempAttributeFormFeature = QgsFeature();
87  if ( !context.parentContext() )
88  {
89  mAttributeEditorScrollArea = new QgsScrollArea();
90  mAttributeEditorScrollArea->setWidgetResizable( true );
91  mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea );
92  mAttributeEditorScrollArea->setWidget( mAttributeForm );
93  }
94  else
95  {
96  mAttributeEditor->layout()->addWidget( mAttributeForm );
97  }
98 
99  connect( mAttributeForm, &QgsAttributeForm::widgetValueChanged, this, &QgsDualView::featureFormAttributeChanged );
100  connect( mAttributeForm, &QgsAttributeForm::modeChanged, this, &QgsDualView::formModeChanged );
101  connect( mMasterModel, &QgsAttributeTableModel::modelChanged, mAttributeForm, &QgsAttributeForm::refreshFeature );
103  connect( mFilterModel, &QgsAttributeTableFilterModel::sortColumnChanged, this, &QgsDualView::onSortColumnChanged );
104 
105  if ( mFeatureListPreviewButton->defaultAction() )
106  mFeatureList->setDisplayExpression( mDisplayExpression );
107  else
108  columnBoxInit();
109 
110  // This slows down load of the attribute table heaps and uses loads of memory.
111  //mTableView->resizeColumnsToContents();
112 
113  mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) );
114 }
115 
116 void QgsDualView::columnBoxInit()
117 {
118  // load fields
119  QList<QgsField> fields = mLayer->fields().toList();
120 
121  QString defaultField;
122 
123  // default expression: saved value
124  QString displayExpression = mLayer->displayExpression();
125 
126  if ( displayExpression.isEmpty() )
127  {
128  // ... there isn't really much to display
129  displayExpression = QStringLiteral( "'[Please define preview text]'" );
130  }
131 
132  mFeatureListPreviewButton->addAction( mActionExpressionPreview );
133  mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
134 
135  Q_FOREACH ( const QgsField &field, fields )
136  {
137  int fieldIndex = mLayer->fields().lookupField( field.name() );
138  if ( fieldIndex == -1 )
139  continue;
140 
141  QString fieldName = field.name();
142  if ( QgsGui::editorWidgetRegistry()->findBest( mLayer, fieldName ).type() != QLatin1String( "Hidden" ) )
143  {
144  QIcon icon = mLayer->fields().iconForField( fieldIndex );
145  QString text = mLayer->attributeDisplayName( fieldIndex );
146 
147  // Generate action for the preview popup button of the feature list
148  QAction *previewAction = new QAction( icon, text, mFeatureListPreviewButton );
149  connect( previewAction, &QAction::triggered, this, [ = ] { previewColumnChanged( previewAction, fieldName ); } );
150  mPreviewColumnsMenu->addAction( previewAction );
151 
152  if ( text == defaultField )
153  {
154  mFeatureListPreviewButton->setDefaultAction( previewAction );
155  }
156  }
157  }
158 
159  QAction *sortByPreviewExpression = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "sort.svg" ) ), tr( "Sort by preview expression" ), this );
160  connect( sortByPreviewExpression, &QAction::triggered, this, &QgsDualView::sortByPreviewExpression );
161  mFeatureListPreviewButton->addAction( sortByPreviewExpression );
162 
163  QAction *separator = new QAction( mFeatureListPreviewButton );
164  separator->setSeparator( true );
165  mFeatureListPreviewButton->addAction( separator );
166  restoreRecentDisplayExpressions();
167 
168  // If there is no single field found as preview
169  if ( !mFeatureListPreviewButton->defaultAction() )
170  {
171  mFeatureList->setDisplayExpression( displayExpression );
172  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
173  setDisplayExpression( mFeatureList->displayExpression() );
174  }
175  else
176  {
177  mFeatureListPreviewButton->defaultAction()->trigger();
178  }
179 }
180 
182 {
183  setCurrentIndex( view );
184 }
185 
187 {
188  return static_cast< QgsDualView::ViewMode >( currentIndex() );
189 }
190 
192 {
193  // cleanup any existing connections
194  switch ( mFilterModel->filterMode() )
195  {
197  disconnect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
198  break;
199 
203  break;
204 
206  disconnect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
207  break;
208  }
209 
210  QgsFeatureRequest r = mMasterModel->request();
211  bool needsGeometry = filterMode == QgsAttributeTableFilterModel::ShowVisible;
212 
213  bool requiresTableReload = ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) // previous request was subset
214  || ( needsGeometry && r.flags() & QgsFeatureRequest::NoGeometry ) // no geometry for last request
215  || ( mMasterModel->rowCount() == 0 ); // no features
216 
217  if ( !needsGeometry )
219  else
223  r.disableFilter();
224 
225  // setup new connections and filter request parameters
226  switch ( filterMode )
227  {
229  connect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
230  if ( mFilterModel->mapCanvas() )
231  {
232  QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
233  r.setFilterRect( rect );
234  }
235  break;
236 
240  break;
241 
243  connect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
244  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
245  break;
246  }
247 
248  if ( requiresTableReload )
249  {
250  mMasterModel->setRequest( r );
251  whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry );
252  mMasterModel->loadLayer();
253  }
254 
255  //update filter model
256  mFilterModel->setFilterMode( filterMode );
257  emit filterChanged();
258 }
259 
260 void QgsDualView::setSelectedOnTop( bool selectedOnTop )
261 {
262  mFilterModel->setSelectedOnTop( selectedOnTop );
263 }
264 
265 void QgsDualView::initLayerCache( bool cacheGeometry )
266 {
267  // Initialize the cache
268  QgsSettings settings;
269  int cacheSize = settings.value( QStringLiteral( "qgis/attributeTableRowCache" ), "10000" ).toInt();
270  mLayerCache = new QgsVectorLayerCache( mLayer, cacheSize, this );
271  mLayerCache->setCacheGeometry( cacheGeometry );
272  if ( 0 == cacheSize || 0 == ( QgsVectorDataProvider::SelectAtId & mLayer->dataProvider()->capabilities() ) )
273  {
274  connect( mLayerCache, &QgsVectorLayerCache::invalidated, this, &QgsDualView::rebuildFullLayerCache );
275  rebuildFullLayerCache();
276  }
277 }
278 
279 void QgsDualView::initModels( QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, bool loadFeatures )
280 {
281  delete mFeatureListModel;
282  delete mFilterModel;
283  delete mMasterModel;
284 
285  mMasterModel = new QgsAttributeTableModel( mLayerCache, this );
286  mMasterModel->setRequest( request );
287  mMasterModel->setEditorContext( mEditorContext );
288  mMasterModel->setExtraColumns( 1 ); // Add one extra column which we can "abuse" as an action column
289 
290  connect( mMasterModel, &QgsAttributeTableModel::progress, this, &QgsDualView::progress );
291  connect( mMasterModel, &QgsAttributeTableModel::finished, this, &QgsDualView::finished );
292 
294 
295  if ( loadFeatures )
296  mMasterModel->loadLayer();
297 
298  mFilterModel = new QgsAttributeTableFilterModel( mapCanvas, mMasterModel, mMasterModel );
299 
300  // The following connections to invalidate() are necessary to keep the filter model in sync
301  // see regression https://issues.qgis.org/issues/15974
302  connect( mMasterModel, &QgsAttributeTableModel::rowsRemoved, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
303  connect( mMasterModel, &QgsAttributeTableModel::rowsInserted, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
304 
306 
307  mFeatureListModel = new QgsFeatureListModel( mFilterModel, mFilterModel );
308  mFeatureListModel->setSortByDisplayExpression( true );
309 }
310 
311 void QgsDualView::restoreRecentDisplayExpressions()
312 {
313  const QVariantList previewExpressions = mLayer->customProperty( QStringLiteral( "dualview/previewExpressions" ) ).toList();
314 
315  for ( const QVariant &previewExpression : previewExpressions )
316  insertRecentlyUsedDisplayExpression( previewExpression.toString() );
317 }
318 
319 void QgsDualView::saveRecentDisplayExpressions() const
320 {
321  if ( ! mLayer )
322  {
323  return;
324  }
325  QList<QAction *> actions = mFeatureListPreviewButton->actions();
326 
327  // Remove existing same action
328  int index = actions.indexOf( mLastDisplayExpressionAction );
329  if ( index != -1 )
330  {
331  QVariantList previewExpressions;
332  for ( ; index < actions.length(); ++index )
333  {
334  QAction *action = actions.at( index );
335  previewExpressions << action->property( "previewExpression" );
336  }
337 
338  mLayer->setCustomProperty( QStringLiteral( "dualview/previewExpressions" ), previewExpressions );
339  }
340 }
341 
342 void QgsDualView::setDisplayExpression( const QString &expression )
343 {
344  mDisplayExpression = expression;
345  insertRecentlyUsedDisplayExpression( expression );
346 }
347 
348 void QgsDualView::insertRecentlyUsedDisplayExpression( const QString &expression )
349 {
350  QList<QAction *> actions = mFeatureListPreviewButton->actions();
351 
352  // Remove existing same action
353  int index = actions.indexOf( mLastDisplayExpressionAction );
354  if ( index != -1 )
355  {
356  for ( int i = 0; index + i < actions.length(); ++i )
357  {
358  QAction *action = actions.at( index );
359  if ( action->text() == expression || i >= 9 )
360  {
361  if ( action == mLastDisplayExpressionAction )
362  mLastDisplayExpressionAction = nullptr;
363  mFeatureListPreviewButton->removeAction( action );
364  }
365  else
366  {
367  if ( !mLastDisplayExpressionAction )
368  mLastDisplayExpressionAction = action;
369  }
370  }
371  }
372 
373  QString name = expression;
374  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) );
375  if ( expression.startsWith( QLatin1String( "COALESCE( \"" ) ) && expression.endsWith( QLatin1String( ", '<NULL>' )" ) ) )
376  {
377  name = expression.mid( 11, expression.length() - 24 ); // Numbers calculated from the COALESCE / <NULL> parts
378 
379  int fieldIndex = mLayer->fields().indexOf( name );
380  if ( fieldIndex != -1 )
381  {
382  name = mLayer->attributeDisplayName( fieldIndex );
383  icon = mLayer->fields().iconForField( fieldIndex );
384  }
385  else
386  {
387  name = expression;
388  }
389  }
390 
391  QAction *previewAction = new QAction( icon, name, mFeatureListPreviewButton );
392  previewAction->setProperty( "previewExpression", expression );
393  connect( previewAction, &QAction::triggered, this, [expression, this]( bool )
394  {
395  setDisplayExpression( expression );
396  mFeatureListPreviewButton->setText( expression );
397  }
398  );
399 
400  mFeatureListPreviewButton->insertAction( mLastDisplayExpressionAction, previewAction );
401  mLastDisplayExpressionAction = previewAction;
402 }
403 
404 void QgsDualView::mFeatureList_aboutToChangeEditSelection( bool &ok )
405 {
406  if ( mLayer->isEditable() && !mAttributeForm->save() )
407  ok = false;
408 }
409 
410 void QgsDualView::mFeatureList_currentEditSelectionChanged( const QgsFeature &feat )
411 {
412  if ( !mAttributeForm )
413  {
414  mTempAttributeFormFeature = feat;
415  }
416  else if ( !mLayer->isEditable() || mAttributeForm->save() )
417  {
418  mAttributeForm->setFeature( feat );
420  }
421  else
422  {
423  // Couldn't save feature
424  }
425 }
426 
428 {
429  mFeatureList->setCurrentFeatureEdited( false );
430  mFeatureList->setEditSelection( fids );
431 }
432 
434 {
435  return mAttributeForm->save();
436 }
437 
439 {
440  mConditionalFormatWidget->setVisible( !mConditionalFormatWidget->isVisible() );
441  mConditionalFormatWidget->viewRules();
442 }
443 
445 {
446  if ( enabled )
448 
450 }
451 
452 void QgsDualView::toggleSearchMode( bool enabled )
453 {
454  if ( enabled )
455  {
457  mAttributeForm->setMode( QgsAttributeForm::SearchMode );
458  }
459  else
460  {
461  mAttributeForm->setMode( QgsAttributeForm::SingleEditMode );
462  }
463 }
464 
465 void QgsDualView::previewExpressionBuilder()
466 {
467  // Show expression builder
469 
470  QgsExpressionBuilderDialog dlg( mLayer, mFeatureList->displayExpression(), this, QStringLiteral( "generic" ), context );
471  dlg.setWindowTitle( tr( "Expression Based Preview" ) );
472  dlg.setExpressionText( mFeatureList->displayExpression() );
473 
474  if ( dlg.exec() == QDialog::Accepted )
475  {
476  mFeatureList->setDisplayExpression( dlg.expressionText() );
477  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
478  mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
479  }
480 
481  setDisplayExpression( mFeatureList->displayExpression() );
482 }
483 
484 void QgsDualView::previewColumnChanged( QAction *previewAction, const QString &expression )
485 {
486  if ( !mFeatureList->setDisplayExpression( QStringLiteral( "COALESCE( \"%1\", '<NULL>' )" ).arg( expression ) ) )
487  {
488  QMessageBox::warning( this,
489  tr( "Column Preview" ),
490  tr( "Could not set column '%1' as preview column.\nParser error:\n%2" )
491  .arg( previewAction->text(), mFeatureList->parserErrorString() )
492  );
493  }
494  else
495  {
496  mFeatureListPreviewButton->setText( previewAction->text() );
497  mFeatureListPreviewButton->setIcon( previewAction->icon() );
498  mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
499  }
500 
501  setDisplayExpression( mFeatureList->displayExpression() );
502 }
503 
505 {
506  return mMasterModel->rowCount();
507 }
508 
510 {
511  return mFilterModel->rowCount();
512 }
513 
515 {
516  QAction *action = qobject_cast<QAction *>( sender() );
517 
518  if ( action && action->data().isValid() && action->data().canConvert<QModelIndex>() )
519  {
520  QModelIndex index = action->data().toModelIndex();
521  QVariant var = masterModel()->data( index, Qt::DisplayRole );
522  QApplication::clipboard()->setText( var.toString() );
523  }
524 }
525 
527 {
528  if ( mProgressDlg )
529  mProgressDlg->cancel();
530 }
531 
532 void QgsDualView::hideEvent( QHideEvent *event )
533 {
534  Q_UNUSED( event )
535  saveRecentDisplayExpressions();
536 }
537 
538 void QgsDualView::viewWillShowContextMenu( QMenu *menu, const QModelIndex &atIndex )
539 {
540  if ( !menu )
541  {
542  return;
543  }
544 
545  QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
546 
547  QAction *copyContentAction = new QAction( tr( "Copy Cell Content" ), this );
548  copyContentAction->setData( QVariant::fromValue<QModelIndex>( sourceIndex ) );
549  menu->addAction( copyContentAction );
550  connect( copyContentAction, &QAction::triggered, this, &QgsDualView::copyCellContent );
551 
552  QgsVectorLayer *vl = mFilterModel->layer();
553  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
554  if ( canvas && vl && vl->geometryType() != QgsWkbTypes::NullGeometry )
555  {
556  menu->addAction( tr( "Zoom to Feature" ), this, SLOT( zoomToCurrentFeature() ) );
557  menu->addAction( tr( "Pan to Feature" ), this, SLOT( panToCurrentFeature() ) );
558  menu->addAction( tr( "Flash Feature" ), this, SLOT( flashCurrentFeature() ) );
559  }
560 
561  //add user-defined actions to context menu
562  QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( "Field" ) );
563  if ( !actions.isEmpty() )
564  {
565  QAction *a = menu->addAction( tr( "Run Layer Action" ) );
566  a->setEnabled( false );
567 
568  Q_FOREACH ( const QgsAction &action, actions )
569  {
570  if ( !action.runable() )
571  continue;
572 
573  if ( vl && !vl->isEditable() && action.isEnabledOnlyWhenEditable() )
574  continue;
575 
576  QgsAttributeTableAction *a = new QgsAttributeTableAction( action.name(), this, action.id(), sourceIndex );
577 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
578  menu->addAction( action.name(), a, SLOT( execute() ) );
579 #else
580  menu->addAction( action.name(), a, &QgsAttributeTableAction::execute );
581 #endif
582  }
583  }
584 
585  //add actions from QgsMapLayerActionRegistry to context menu
586  QList<QgsMapLayerAction *> registeredActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer );
587  if ( !registeredActions.isEmpty() )
588  {
589  //add a separator between user defined and standard actions
590  menu->addSeparator();
591 
592  Q_FOREACH ( QgsMapLayerAction *action, registeredActions )
593  {
594  QgsAttributeTableMapLayerAction *a = new QgsAttributeTableMapLayerAction( action->text(), this, action, sourceIndex );
595 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
596  menu->addAction( action->text(), a, SLOT( execut() ) );
597 #else
598  menu->addAction( action->text(), a, &QgsAttributeTableMapLayerAction::execute );
599 #endif
600  }
601  }
602 
603  menu->addSeparator();
604  QgsAttributeTableAction *a = new QgsAttributeTableAction( tr( "Open Form" ), this, QString(), sourceIndex );
605 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
606  menu->addAction( tr( "Open Form" ), a, SLOT( featureForm() ) );
607 #else
608  menu->addAction( tr( "Open Form" ), a, &QgsAttributeTableAction::featureForm );
609 #endif
610 }
611 
612 
613 void QgsDualView::widgetWillShowContextMenu( QgsActionMenu *menu, const QModelIndex &atIndex )
614 {
615  emit showContextMenuExternally( menu, mFilterModel->rowToId( atIndex ) );
616 }
617 
618 
619 void QgsDualView::showViewHeaderMenu( QPoint point )
620 {
621  int col = mTableView->columnAt( point.x() );
622 
623  delete mHorizontalHeaderMenu;
624  mHorizontalHeaderMenu = new QMenu( this );
625 
626  QAction *hide = new QAction( tr( "&Hide Column" ), mHorizontalHeaderMenu );
627  connect( hide, &QAction::triggered, this, &QgsDualView::hideColumn );
628  hide->setData( col );
629  mHorizontalHeaderMenu->addAction( hide );
630  QAction *setWidth = new QAction( tr( "&Set Width…" ), mHorizontalHeaderMenu );
631  connect( setWidth, &QAction::triggered, this, &QgsDualView::resizeColumn );
632  setWidth->setData( col );
633  mHorizontalHeaderMenu->addAction( setWidth );
634  QAction *optimizeWidth = new QAction( tr( "&Autosize" ), mHorizontalHeaderMenu );
635  connect( optimizeWidth, &QAction::triggered, this, &QgsDualView::autosizeColumn );
636  optimizeWidth->setData( col );
637  mHorizontalHeaderMenu->addAction( optimizeWidth );
638 
639  mHorizontalHeaderMenu->addSeparator();
640  QAction *organize = new QAction( tr( "&Organize Columns…" ), mHorizontalHeaderMenu );
641  connect( organize, &QAction::triggered, this, &QgsDualView::organizeColumns );
642  mHorizontalHeaderMenu->addAction( organize );
643  QAction *sort = new QAction( tr( "&Sort…" ), mHorizontalHeaderMenu );
644  connect( sort, &QAction::triggered, this, &QgsDualView::modifySort );
645  mHorizontalHeaderMenu->addAction( sort );
646 
647  mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
648 }
649 
650 void QgsDualView::organizeColumns()
651 {
652  if ( !mLayer )
653  {
654  return;
655  }
656 
657  QgsOrganizeTableColumnsDialog dialog( mLayer, this );
658  if ( dialog.exec() == QDialog::Accepted )
659  {
660  QgsAttributeTableConfig config = dialog.config();
661  setAttributeTableConfig( config );
662  }
663 }
664 
665 void QgsDualView::tableColumnResized( int column, int width )
666 {
667  QgsAttributeTableConfig config = mConfig;
668  int sourceCol = config.mapVisibleColumnToIndex( column );
669  if ( sourceCol >= 0 && config.columnWidth( sourceCol ) != width )
670  {
671  config.setColumnWidth( sourceCol, width );
672  setAttributeTableConfig( config );
673  }
674 }
675 
676 void QgsDualView::hideColumn()
677 {
678  QAction *action = qobject_cast<QAction *>( sender() );
679  int col = action->data().toInt();
680  QgsAttributeTableConfig config = mConfig;
681  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
682  if ( sourceCol >= 0 )
683  {
684  config.setColumnHidden( sourceCol, true );
685  setAttributeTableConfig( config );
686  }
687 }
688 
689 void QgsDualView::resizeColumn()
690 {
691  QAction *action = qobject_cast<QAction *>( sender() );
692  int col = action->data().toInt();
693  if ( col < 0 )
694  return;
695 
696  QgsAttributeTableConfig config = mConfig;
697  int sourceCol = config.mapVisibleColumnToIndex( col );
698  if ( sourceCol >= 0 )
699  {
700  bool ok = false;
701  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
702  mTableView->columnWidth( col ),
703  0, 1000, 10, &ok );
704  if ( ok )
705  {
706  config.setColumnWidth( sourceCol, width );
707  setAttributeTableConfig( config );
708  }
709  }
710 }
711 
712 void QgsDualView::autosizeColumn()
713 {
714  QAction *action = qobject_cast<QAction *>( sender() );
715  int col = action->data().toInt();
716  mTableView->resizeColumnToContents( col );
717 }
718 
719 void QgsDualView::modifySort()
720 {
721  if ( !mLayer )
722  return;
723 
724  QgsAttributeTableConfig config = mConfig;
725 
726  QDialog orderByDlg;
727  orderByDlg.setWindowTitle( tr( "Configure Attribute Table Sort Order" ) );
728  QDialogButtonBox *dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
729  QGridLayout *layout = new QGridLayout();
730  connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
731  connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
732  orderByDlg.setLayout( layout );
733 
734  QGroupBox *sortingGroupBox = new QGroupBox();
735  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
736  sortingGroupBox->setCheckable( true );
737  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
738  layout->addWidget( sortingGroupBox );
739  sortingGroupBox->setLayout( new QGridLayout() );
740 
741  QgsExpressionBuilderWidget *expressionBuilder = new QgsExpressionBuilderWidget();
743  expressionBuilder->setExpressionContext( context );
744  expressionBuilder->setLayer( mLayer );
745  expressionBuilder->loadFieldNames();
746  expressionBuilder->loadRecent( QStringLiteral( "generic" ) );
747  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? mLayer->displayExpression() : sortExpression() );
748 
749  sortingGroupBox->layout()->addWidget( expressionBuilder );
750 
751  QCheckBox *cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
752  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
753  sortingGroupBox->layout()->addWidget( cbxSortAscending );
754 
755  layout->addWidget( dialogButtonBox );
756  if ( orderByDlg.exec() )
757  {
758  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
759  if ( sortingGroupBox->isChecked() )
760  {
761  setSortExpression( expressionBuilder->expressionText(), sortOrder );
762  config.setSortExpression( expressionBuilder->expressionText() );
763  config.setSortOrder( sortOrder );
764  }
765  else
766  {
767  setSortExpression( QString(), sortOrder );
768  config.setSortExpression( QString() );
769  }
770 
771  setAttributeTableConfig( config );
772  }
773 }
774 
775 void QgsDualView::zoomToCurrentFeature()
776 {
777  QModelIndex currentIndex = mTableView->currentIndex();
778  if ( !currentIndex.isValid() )
779  {
780  return;
781  }
782 
783  QgsFeatureIds ids;
784  ids.insert( mFilterModel->rowToId( currentIndex ) );
785  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
786  if ( canvas )
787  {
788  canvas->zoomToFeatureIds( mLayer, ids );
789  }
790 }
791 
792 void QgsDualView::panToCurrentFeature()
793 {
794  QModelIndex currentIndex = mTableView->currentIndex();
795  if ( !currentIndex.isValid() )
796  {
797  return;
798  }
799 
800  QgsFeatureIds ids;
801  ids.insert( mFilterModel->rowToId( currentIndex ) );
802  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
803  if ( canvas )
804  {
805  canvas->panToFeatureIds( mLayer, ids );
806  }
807 }
808 
809 void QgsDualView::flashCurrentFeature()
810 {
811  QModelIndex currentIndex = mTableView->currentIndex();
812  if ( !currentIndex.isValid() )
813  {
814  return;
815  }
816 
817  QgsFeatureIds ids;
818  ids.insert( mFilterModel->rowToId( currentIndex ) );
819  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
820  if ( canvas )
821  {
822  canvas->flashFeatureIds( mLayer, ids );
823  }
824 }
825 
826 void QgsDualView::rebuildFullLayerCache()
827 {
828  connect( mLayerCache, &QgsVectorLayerCache::progress, this, &QgsDualView::progress, Qt::UniqueConnection );
829  connect( mLayerCache, &QgsVectorLayerCache::finished, this, &QgsDualView::finished, Qt::UniqueConnection );
830 
831  mLayerCache->setFullCache( true );
832 }
833 
834 void QgsDualView::previewExpressionChanged( const QString &expression )
835 {
836  mLayer->setDisplayExpression( expression );
837 }
838 
839 void QgsDualView::onSortColumnChanged()
840 {
841  QgsAttributeTableConfig cfg = mLayer->attributeTableConfig();
842  if ( cfg.sortExpression() != mFilterModel->sortExpression() ||
843  cfg.sortOrder() != mFilterModel->sortOrder() )
844  {
845  cfg.setSortExpression( mFilterModel->sortExpression() );
846  cfg.setSortOrder( mFilterModel->sortOrder() );
848  }
849 }
850 
851 void QgsDualView::sortByPreviewExpression()
852 {
853  Qt::SortOrder sortOrder = Qt::AscendingOrder;
854  if ( mFeatureList->displayExpression() == sortExpression() )
855  {
856  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
857  }
858  setSortExpression( mFeatureList->displayExpression(), sortOrder );
859 }
860 
861 void QgsDualView::updateSelectedFeatures()
862 {
863  QgsFeatureRequest r = mMasterModel->request();
865  return; // already requested all features
866 
867  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
868  mMasterModel->setRequest( r );
869  mMasterModel->loadLayer();
870  emit filterChanged();
871 }
872 
873 void QgsDualView::extentChanged()
874 {
875  QgsFeatureRequest r = mMasterModel->request();
876  if ( mFilterModel->mapCanvas() && ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) )
877  {
878  QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
879  r.setFilterRect( rect );
880  mMasterModel->setRequest( r );
881  mMasterModel->loadLayer();
882  }
883  emit filterChanged();
884 }
885 
886 void QgsDualView::featureFormAttributeChanged( const QString &attribute, const QVariant &value, bool attributeChanged )
887 {
888  Q_UNUSED( attribute );
889  Q_UNUSED( value );
890  if ( attributeChanged )
891  mFeatureList->setCurrentFeatureEdited( true );
892 }
893 
895 {
896  mFilterModel->setFilteredFeatures( filteredFeatures );
897 }
898 
900 {
901  mMasterModel->setRequest( request );
902 }
903 
905 {
906  mTableView->setFeatureSelectionManager( featureSelectionManager );
907  mFeatureList->setFeatureSelectionManager( featureSelectionManager );
908 
909  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
910  delete mFeatureSelectionManager;
911 
912  mFeatureSelectionManager = featureSelectionManager;
913 }
914 
916 {
917  mConfig = config;
918  mConfig.update( mLayer->fields() );
919  mLayer->setAttributeTableConfig( mConfig );
920  mFilterModel->setAttributeTableConfig( mConfig );
921  mTableView->setAttributeTableConfig( mConfig );
922 }
923 
924 void QgsDualView::setSortExpression( const QString &sortExpression, Qt::SortOrder sortOrder )
925 {
926  if ( sortExpression.isNull() )
927  mFilterModel->sort( -1 );
928  else
929  mFilterModel->sort( sortExpression, sortOrder );
930 
931  mConfig.setSortExpression( sortExpression );
932  mConfig.setSortOrder( sortOrder );
933  setAttributeTableConfig( mConfig );
934 }
935 
937 {
938  return mFilterModel->sortExpression();
939 }
940 
941 void QgsDualView::progress( int i, bool &cancel )
942 {
943  if ( !mProgressDlg )
944  {
945  mProgressDlg = new QProgressDialog( tr( "Loading features…" ), tr( "Abort" ), 0, 0, this );
946  mProgressDlg->setWindowTitle( tr( "Attribute Table" ) );
947  mProgressDlg->setWindowModality( Qt::WindowModal );
948  mProgressDlg->show();
949  }
950 
951  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
952  QCoreApplication::processEvents();
953 
954  cancel = mProgressDlg && mProgressDlg->wasCanceled();
955 }
956 
957 void QgsDualView::finished()
958 {
959  delete mProgressDlg;
960  mProgressDlg = nullptr;
961 }
962 
963 /*
964  * QgsAttributeTableAction
965  */
966 
968 {
969  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
970 }
971 
973 {
974  QgsFeatureIds editedIds;
975  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
976  mDualView->setCurrentEditSelection( editedIds );
977  mDualView->setView( QgsDualView::AttributeEditor );
978 }
979 
980 /*
981  * QgsAttributeTableMapLayerAction
982  */
983 
985 {
986  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
987 }
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:40
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
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: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: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.
Multi edit mode, for editing fields of multiple features at once.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:544
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: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
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.
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
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:47
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()
Gets 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 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 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: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.
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: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)
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.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:429
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
void setSortByDisplayExpression(bool sortByDisplayExpression)
Sort this model by its display expression.
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
Gets 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
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:67
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)
Sets flags that affect how features will be fetched.
void rulesUpdated(const QString &fieldName)
Emitted when the conditional styling rules are updated.