QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 <QClipboard>
17 #include <QDialog>
18 #include <QMenu>
19 #include <QMessageBox>
20 #include <QProgressDialog>
21 #include <QGroupBox>
22 #include <QInputDialog>
23 #include <QTimer>
24 #include <QShortcut>
25 
26 #include "qgsapplication.h"
27 #include "qgsactionmanager.h"
28 #include "qgsattributetablemodel.h"
29 #include "qgsdualview.h"
31 #include "qgsfeaturelistmodel.h"
33 #include "qgsmapcanvas.h"
35 #include "qgsmessagelog.h"
36 #include "qgsvectordataprovider.h"
37 #include "qgsvectorlayercache.h"
40 #include "qgssettings.h"
41 #include "qgsscrollarea.h"
42 #include "qgsgui.h"
44 #include "qgsshortcutsmanager.h"
46 
47 
48 QgsDualView::QgsDualView( QWidget *parent )
49  : QStackedWidget( parent )
50 {
51  setupUi( this );
52  connect( mFeatureListView, &QgsFeatureListView::aboutToChangeEditSelection, this, &QgsDualView::featureListAboutToChangeEditSelection );
53  connect( mFeatureListView, &QgsFeatureListView::currentEditSelectionChanged, this, &QgsDualView::featureListCurrentEditSelectionChanged );
54  connect( mFeatureListView, &QgsFeatureListView::currentEditSelectionProgressChanged, this, &QgsDualView::updateEditSelectionProgress );
55 
56  mConditionalFormatWidgetStack->hide();
57  mConditionalFormatWidget = new QgsFieldConditionalFormatWidget( this );
58  mConditionalFormatWidgetStack->setMainPanel( mConditionalFormatWidget );
59  mConditionalFormatWidget->setDockMode( true );
60 
61  QgsSettings settings;
62  mConditionalSplitter->restoreState( settings.value( QStringLiteral( "/qgis/attributeTable/splitterState" ), QByteArray() ).toByteArray() );
63 
64  mPreviewColumnsMenu = new QMenu( this );
65  mActionPreviewColumnsMenu->setMenu( mPreviewColumnsMenu );
66 
67  // Set preview icon
68  mActionExpressionPreview->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) ) );
69 
70  // Connect layer list preview signals
71  connect( mActionExpressionPreview, &QAction::triggered, this, &QgsDualView::previewExpressionBuilder );
72  connect( mFeatureListView, &QgsFeatureListView::displayExpressionChanged, this, &QgsDualView::previewExpressionChanged );
73 
74  // browsing toolbar
75  connect( mNextFeatureButton, &QToolButton::clicked, mFeatureListView, &QgsFeatureListView::editNextFeature );
76  connect( mPreviousFeatureButton, &QToolButton::clicked, mFeatureListView, &QgsFeatureListView::editPreviousFeature );
77  connect( mFirstFeatureButton, &QToolButton::clicked, mFeatureListView, &QgsFeatureListView::editFirstFeature );
78  connect( mLastFeatureButton, &QToolButton::clicked, mFeatureListView, &QgsFeatureListView::editLastFeature );
79 
80  auto createShortcuts = [ = ]( const QString & objectName, void ( QgsFeatureListView::* slot )() )
81  {
82  QShortcut *sc = QgsGui::shortcutsManager()->shortcutByName( objectName );
83  // do not assert for sc as it would lead to crashes in testing
84  // or when using custom widgets lib if built with Debug
85  if ( sc )
86  connect( sc, &QShortcut::activated, mFeatureListView, slot );
87  };
88  createShortcuts( QStringLiteral( "mAttributeTableFirstEditedFeature" ), &QgsFeatureListView::editFirstFeature );
89  createShortcuts( QStringLiteral( "mAttributeTablePreviousEditedFeature" ), &QgsFeatureListView::editPreviousFeature );
90  createShortcuts( QStringLiteral( "mAttributeTableNextEditedFeature" ), &QgsFeatureListView::editNextFeature );
91  createShortcuts( QStringLiteral( "mAttributeTableLastEditedFeature" ), &QgsFeatureListView::editLastFeature );
92 
93  QButtonGroup *buttonGroup = new QButtonGroup( this );
94  buttonGroup->setExclusive( false );
95  buttonGroup->addButton( mAutoPanButton, PanToFeature );
96  buttonGroup->addButton( mAutoZoomButton, ZoomToFeature );
97  FeatureListBrowsingAction action = QgsSettings().enumValue( QStringLiteral( "/qgis/attributeTable/featureListBrowsingAction" ), NoAction );
98  QAbstractButton *bt = buttonGroup->button( static_cast<int>( action ) );
99  if ( bt )
100  bt->setChecked( true );
101  connect( buttonGroup, qgis::overload< QAbstractButton *, bool >::of( &QButtonGroup::buttonToggled ), this, &QgsDualView::panZoomGroupButtonToggled );
102  mFlashButton->setChecked( QgsSettings().value( QStringLiteral( "/qgis/attributeTable/featureListHighlightFeature" ), true ).toBool() );
103  connect( mFlashButton, &QToolButton::clicked, this, &QgsDualView::flashButtonClicked );
104 }
105 
107 {
108  QgsSettings settings;
109  settings.setValue( QStringLiteral( "/qgis/attributeTable/splitterState" ), mConditionalSplitter->saveState() );
110 }
111 
112 void QgsDualView::init( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request,
113  const QgsAttributeEditorContext &context, bool loadFeatures )
114 {
115  if ( !layer )
116  return;
117 
118  mLayer = layer;
119  mEditorContext = context;
120 
121  connect( mTableView, &QgsAttributeTableView::willShowContextMenu, this, &QgsDualView::viewWillShowContextMenu );
122  mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
123  connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &QgsDualView::showViewHeaderMenu );
124  connect( mTableView, &QgsAttributeTableView::columnResized, this, &QgsDualView::tableColumnResized );
125  connect( mFeatureListView, &QgsFeatureListView::willShowContextMenu, this, &QgsDualView::widgetWillShowContextMenu );
126 
127  initLayerCache( !( request.flags() & QgsFeatureRequest::NoGeometry ) || !request.filterRect().isNull() );
128  initModels( mapCanvas, request, loadFeatures );
129 
130  mConditionalFormatWidget->setLayer( mLayer );
131 
132  mTableView->setModel( mFilterModel );
133  mFeatureListView->setModel( mFeatureListModel );
134  delete mAttributeForm;
135  mAttributeForm = new QgsAttributeForm( mLayer, mTempAttributeFormFeature, mEditorContext );
136  mTempAttributeFormFeature = QgsFeature();
137  if ( !context.parentContext() )
138  {
139  mAttributeEditorScrollArea = new QgsScrollArea();
140  mAttributeEditorScrollArea->setWidgetResizable( true );
141  mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea );
142  mAttributeEditorScrollArea->setWidget( mAttributeForm );
143  }
144  else
145  {
146  mAttributeEditor->layout()->addWidget( mAttributeForm );
147  }
148 
149  connect( mAttributeForm, &QgsAttributeForm::widgetValueChanged, this, &QgsDualView::featureFormAttributeChanged );
150  connect( mAttributeForm, &QgsAttributeForm::modeChanged, this, &QgsDualView::formModeChanged );
151  connect( mMasterModel, &QgsAttributeTableModel::modelChanged, mAttributeForm, &QgsAttributeForm::refreshFeature );
153  connect( mFilterModel, &QgsAttributeTableFilterModel::sortColumnChanged, this, &QgsDualView::onSortColumnChanged );
154 
155  if ( mFeatureListPreviewButton->defaultAction() )
156  mFeatureListView->setDisplayExpression( mDisplayExpression );
157  else
158  columnBoxInit();
159 
160  // This slows down load of the attribute table heaps and uses loads of memory.
161  //mTableView->resizeColumnsToContents();
162 }
163 
164 void QgsDualView::columnBoxInit()
165 {
166  // load fields
167  QList<QgsField> fields = mLayer->fields().toList();
168 
169  QString defaultField;
170 
171  // default expression: saved value
172  QString displayExpression = mLayer->displayExpression();
173 
174  if ( displayExpression.isEmpty() )
175  {
176  // ... there isn't really much to display
177  displayExpression = QStringLiteral( "'[Please define preview text]'" );
178  }
179 
180  mFeatureListPreviewButton->addAction( mActionExpressionPreview );
181  mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
182 
183  const auto constFields = fields;
184  for ( const QgsField &field : constFields )
185  {
186  int fieldIndex = mLayer->fields().lookupField( field.name() );
187  if ( fieldIndex == -1 )
188  continue;
189 
190  QString fieldName = field.name();
191  if ( QgsGui::editorWidgetRegistry()->findBest( mLayer, fieldName ).type() != QLatin1String( "Hidden" ) )
192  {
193  QIcon icon = mLayer->fields().iconForField( fieldIndex );
194  QString text = mLayer->attributeDisplayName( fieldIndex );
195 
196  // Generate action for the preview popup button of the feature list
197  QAction *previewAction = new QAction( icon, text, mFeatureListPreviewButton );
198  connect( previewAction, &QAction::triggered, this, [ = ] { previewColumnChanged( previewAction, fieldName ); } );
199  mPreviewColumnsMenu->addAction( previewAction );
200 
201  if ( text == defaultField )
202  {
203  mFeatureListPreviewButton->setDefaultAction( previewAction );
204  }
205  }
206  }
207 
208  QAction *sortByPreviewExpression = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "sort.svg" ) ), tr( "Sort by preview expression" ), this );
209  connect( sortByPreviewExpression, &QAction::triggered, this, &QgsDualView::sortByPreviewExpression );
210  mFeatureListPreviewButton->addAction( sortByPreviewExpression );
211 
212  QAction *separator = new QAction( mFeatureListPreviewButton );
213  separator->setSeparator( true );
214  mFeatureListPreviewButton->addAction( separator );
215  restoreRecentDisplayExpressions();
216 
217  // If there is no single field found as preview
218  if ( !mFeatureListPreviewButton->defaultAction() )
219  {
220  mFeatureListView->setDisplayExpression( displayExpression );
221  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
222  setDisplayExpression( mFeatureListView->displayExpression() );
223  }
224  else
225  {
226  mFeatureListPreviewButton->defaultAction()->trigger();
227  }
228 }
229 
231 {
232  setCurrentIndex( view );
233 }
234 
236 {
237  return static_cast< QgsDualView::ViewMode >( currentIndex() );
238 }
239 
241 {
242  // cleanup any existing connections
243  switch ( mFilterModel->filterMode() )
244  {
246  disconnect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
247  break;
248 
252  break;
253 
255  disconnect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
256  break;
257  }
258 
259  QgsFeatureRequest r = mMasterModel->request();
260  bool needsGeometry = filterMode == QgsAttributeTableFilterModel::ShowVisible;
261 
262  bool requiresTableReload = ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) // previous request was subset
263  || ( needsGeometry && r.flags() & QgsFeatureRequest::NoGeometry ) // no geometry for last request
264  || ( mMasterModel->rowCount() == 0 ); // no features
265 
266  if ( !needsGeometry )
268  else
272  r.disableFilter();
273 
274  // setup new connections and filter request parameters
275  switch ( filterMode )
276  {
278  connect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
279  if ( mFilterModel->mapCanvas() )
280  {
281  QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
282  r.setFilterRect( rect );
283  }
284  break;
285 
289  break;
290 
292  connect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
293  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
294  break;
295  }
296 
297  if ( requiresTableReload )
298  {
299  mMasterModel->setRequest( r );
300  whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry );
301  mMasterModel->loadLayer();
302  }
303 
304  //update filter model
305  mFilterModel->setFilterMode( filterMode );
306  emit filterChanged();
307 }
308 
309 void QgsDualView::setSelectedOnTop( bool selectedOnTop )
310 {
311  mFilterModel->setSelectedOnTop( selectedOnTop );
312 }
313 
314 void QgsDualView::initLayerCache( bool cacheGeometry )
315 {
316  // Initialize the cache
317  QgsSettings settings;
318  int cacheSize = settings.value( QStringLiteral( "qgis/attributeTableRowCache" ), "10000" ).toInt();
319  mLayerCache = new QgsVectorLayerCache( mLayer, cacheSize, this );
320  mLayerCache->setCacheGeometry( cacheGeometry );
321  if ( 0 == cacheSize || 0 == ( QgsVectorDataProvider::SelectAtId & mLayer->dataProvider()->capabilities() ) )
322  {
323  connect( mLayerCache, &QgsVectorLayerCache::invalidated, this, &QgsDualView::rebuildFullLayerCache );
324  rebuildFullLayerCache();
325  }
326 }
327 
328 void QgsDualView::initModels( QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, bool loadFeatures )
329 {
330  delete mFeatureListModel;
331  delete mFilterModel;
332  delete mMasterModel;
333 
334  mMasterModel = new QgsAttributeTableModel( mLayerCache, this );
335  mMasterModel->setRequest( request );
336  mMasterModel->setEditorContext( mEditorContext );
337  mMasterModel->setExtraColumns( 1 ); // Add one extra column which we can "abuse" as an action column
338 
339  connect( mMasterModel, &QgsAttributeTableModel::progress, this, &QgsDualView::progress );
340  connect( mMasterModel, &QgsAttributeTableModel::finished, this, &QgsDualView::finished );
341 
343 
344  if ( loadFeatures )
345  mMasterModel->loadLayer();
346 
347  mFilterModel = new QgsAttributeTableFilterModel( mapCanvas, mMasterModel, mMasterModel );
348 
349  // The following connections to invalidate() are necessary to keep the filter model in sync
350  // see regression https://github.com/qgis/QGIS/issues/23890
351  connect( mMasterModel, &QgsAttributeTableModel::rowsRemoved, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
352  connect( mMasterModel, &QgsAttributeTableModel::rowsInserted, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
353 
355 
356  mFeatureListModel = new QgsFeatureListModel( mFilterModel, mFilterModel );
357  mFeatureListModel->setSortByDisplayExpression( true );
358 }
359 
360 void QgsDualView::restoreRecentDisplayExpressions()
361 {
362  const QVariantList previewExpressions = mLayer->customProperty( QStringLiteral( "dualview/previewExpressions" ) ).toList();
363 
364  for ( const QVariant &previewExpression : previewExpressions )
365  insertRecentlyUsedDisplayExpression( previewExpression.toString() );
366 }
367 
368 void QgsDualView::saveRecentDisplayExpressions() const
369 {
370  if ( ! mLayer )
371  {
372  return;
373  }
374  QList<QAction *> actions = mFeatureListPreviewButton->actions();
375 
376  // Remove existing same action
377  int index = actions.indexOf( mLastDisplayExpressionAction );
378  if ( index != -1 )
379  {
380  QVariantList previewExpressions;
381  for ( ; index < actions.length(); ++index )
382  {
383  QAction *action = actions.at( index );
384  previewExpressions << action->property( "previewExpression" );
385  }
386 
387  mLayer->setCustomProperty( QStringLiteral( "dualview/previewExpressions" ), previewExpressions );
388  }
389 }
390 
391 void QgsDualView::setDisplayExpression( const QString &expression )
392 {
393  mDisplayExpression = expression;
394  insertRecentlyUsedDisplayExpression( expression );
395 }
396 
397 void QgsDualView::insertRecentlyUsedDisplayExpression( const QString &expression )
398 {
399  QList<QAction *> actions = mFeatureListPreviewButton->actions();
400 
401  // Remove existing same action
402  int index = actions.indexOf( mLastDisplayExpressionAction );
403  if ( index != -1 )
404  {
405  for ( int i = 0; index + i < actions.length(); ++i )
406  {
407  QAction *action = actions.at( index );
408  if ( action->text() == expression || i >= 9 )
409  {
410  if ( action == mLastDisplayExpressionAction )
411  mLastDisplayExpressionAction = nullptr;
412  mFeatureListPreviewButton->removeAction( action );
413  }
414  else
415  {
416  if ( !mLastDisplayExpressionAction )
417  mLastDisplayExpressionAction = action;
418  }
419  }
420  }
421 
422  QString name = expression;
423  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) );
424  if ( expression.startsWith( QLatin1String( "COALESCE( \"" ) ) && expression.endsWith( QLatin1String( ", '<NULL>' )" ) ) )
425  {
426  name = expression.mid( 11, expression.length() - 24 ); // Numbers calculated from the COALESCE / <NULL> parts
427 
428  int fieldIndex = mLayer->fields().indexOf( name );
429  if ( fieldIndex != -1 )
430  {
431  name = mLayer->attributeDisplayName( fieldIndex );
432  icon = mLayer->fields().iconForField( fieldIndex );
433  }
434  else
435  {
436  name = expression;
437  }
438  }
439 
440  QAction *previewAction = new QAction( icon, name, mFeatureListPreviewButton );
441  previewAction->setProperty( "previewExpression", expression );
442  connect( previewAction, &QAction::triggered, this, [expression, this]( bool )
443  {
444  setDisplayExpression( expression );
445  mFeatureListPreviewButton->setText( expression );
446  }
447  );
448 
449  mFeatureListPreviewButton->insertAction( mLastDisplayExpressionAction, previewAction );
450  mLastDisplayExpressionAction = previewAction;
451 }
452 
453 void QgsDualView::updateEditSelectionProgress( int progress, int count )
454 {
455  mProgressCount->setText( QStringLiteral( "%1 / %2" ).arg( progress + 1 ).arg( count ) );
456  mPreviousFeatureButton->setEnabled( progress > 0 );
457  mNextFeatureButton->setEnabled( progress + 1 < count );
458  mFirstFeatureButton->setEnabled( progress > 0 );
459  mLastFeatureButton->setEnabled( progress + 1 < count );
460 }
461 
462 void QgsDualView::panOrZoomToFeature( const QgsFeatureIds &featureset )
463 {
464  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
465  if ( canvas && view() == AttributeEditor && featureset != mLastFeatureSet )
466  {
468  {
469  if ( mAutoPanButton->isChecked() )
470  QTimer::singleShot( 0, this, [ = ]()
471  {
472  canvas->panToFeatureIds( mLayer, featureset, false );
473  } );
474  else if ( mAutoZoomButton->isChecked() )
475  QTimer::singleShot( 0, this, [ = ]()
476  {
477  canvas->zoomToFeatureIds( mLayer, featureset );
478  } );
479  }
480  if ( mFlashButton->isChecked() )
481  QTimer::singleShot( 0, this, [ = ]()
482  {
483  canvas->flashFeatureIds( mLayer, featureset );
484  } );
485  mLastFeatureSet = featureset;
486  }
487 }
488 
489 void QgsDualView::panZoomGroupButtonToggled( QAbstractButton *button, bool checked )
490 {
491  if ( button == mAutoPanButton && checked )
492  {
493  QgsSettings().setEnumValue( QStringLiteral( "/qgis/attributeTable/featureListBrowsingAction" ), PanToFeature );
494  mAutoZoomButton->setChecked( false );
495  }
496  else if ( button == mAutoZoomButton && checked )
497  {
498  QgsSettings().setEnumValue( QStringLiteral( "/qgis/attributeTable/featureListBrowsingAction" ), ZoomToFeature );
499  mAutoPanButton->setChecked( false );
500  }
501  else
502  {
503  QgsSettings().setEnumValue( QStringLiteral( "/qgis/attributeTable/featureListBrowsingAction" ), NoAction );
504  }
505 
506  if ( checked )
507  panOrZoomToFeature( mFeatureListView->currentEditSelection() );
508 }
509 
510 void QgsDualView::flashButtonClicked( bool clicked )
511 {
512  QgsSettings().setValue( QStringLiteral( "/qgis/attributeTable/featureListHighlightFeature" ), clicked );
513  if ( !clicked )
514  return;
515 
516  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
517 
518  if ( canvas )
519  canvas->flashFeatureIds( mLayer, mFeatureListView->currentEditSelection() );
520 }
521 
522 void QgsDualView::featureListAboutToChangeEditSelection( bool &ok )
523 {
524  if ( mLayer->isEditable() && !mAttributeForm->save() )
525  ok = false;
526 }
527 
528 void QgsDualView::featureListCurrentEditSelectionChanged( const QgsFeature &feat )
529 {
530  if ( !mAttributeForm )
531  {
532  mTempAttributeFormFeature = feat;
533  }
534  else if ( !mLayer->isEditable() || mAttributeForm->save() )
535  {
536  mAttributeForm->setFeature( feat );
537  QgsFeatureIds featureset;
538  featureset << feat.id();
539  setCurrentEditSelection( featureset );
540 
541  panOrZoomToFeature( featureset );
542 
543  }
544  else
545  {
546  // Couldn't save feature
547  }
548 }
549 
551 {
552  mFeatureListView->setCurrentFeatureEdited( false );
553  mFeatureListView->setEditSelection( fids );
554 }
555 
557 {
558  return mAttributeForm->save();
559 }
560 
562 {
563  mConditionalFormatWidgetStack->setVisible( !mConditionalFormatWidgetStack->isVisible() );
564 }
565 
567 {
568  if ( enabled )
570 
572 }
573 
574 void QgsDualView::toggleSearchMode( bool enabled )
575 {
576  if ( enabled )
577  {
580  }
581  else
582  {
584  }
585 }
586 
587 void QgsDualView::previewExpressionBuilder()
588 {
589  // Show expression builder
591 
592  QgsExpressionBuilderDialog dlg( mLayer, mFeatureListView->displayExpression(), this, QStringLiteral( "generic" ), context );
593  dlg.setWindowTitle( tr( "Expression Based Preview" ) );
594  dlg.setExpressionText( mFeatureListView->displayExpression() );
595 
596  if ( dlg.exec() == QDialog::Accepted )
597  {
598  mFeatureListView->setDisplayExpression( dlg.expressionText() );
599  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
600  mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
601  }
602 
603  setDisplayExpression( mFeatureListView->displayExpression() );
604 }
605 
606 void QgsDualView::previewColumnChanged( QAction *previewAction, const QString &expression )
607 {
608  if ( !mFeatureListView->setDisplayExpression( QStringLiteral( "COALESCE( \"%1\", '<NULL>' )" ).arg( expression ) ) )
609  {
610  QMessageBox::warning( this,
611  tr( "Column Preview" ),
612  tr( "Could not set column '%1' as preview column.\nParser error:\n%2" )
613  .arg( previewAction->text(), mFeatureListView->parserErrorString() )
614  );
615  }
616  else
617  {
618  mFeatureListPreviewButton->setText( previewAction->text() );
619  mFeatureListPreviewButton->setIcon( previewAction->icon() );
620  mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
621  }
622 
623  setDisplayExpression( mFeatureListView->displayExpression() );
624 }
625 
627 {
628  return mMasterModel->rowCount();
629 }
630 
632 {
633  return mFilterModel->rowCount();
634 }
635 
637 {
638  QAction *action = qobject_cast<QAction *>( sender() );
639 
640  if ( action && action->data().isValid() && action->data().canConvert<QModelIndex>() )
641  {
642  QModelIndex index = action->data().toModelIndex();
643  QVariant var = masterModel()->data( index, Qt::DisplayRole );
644  QApplication::clipboard()->setText( var.toString() );
645  }
646 }
647 
649 {
650  if ( mProgressDlg )
651  mProgressDlg->cancel();
652 }
653 
654 void QgsDualView::hideEvent( QHideEvent *event )
655 {
656  Q_UNUSED( event )
657  saveRecentDisplayExpressions();
658 }
659 
660 void QgsDualView::viewWillShowContextMenu( QMenu *menu, const QModelIndex &atIndex )
661 {
662  if ( !menu )
663  {
664  return;
665  }
666 
667  QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
668 
669  QAction *copyContentAction = new QAction( tr( "Copy Cell Content" ), this );
670  copyContentAction->setData( QVariant::fromValue<QModelIndex>( sourceIndex ) );
671  menu->addAction( copyContentAction );
672  connect( copyContentAction, &QAction::triggered, this, &QgsDualView::copyCellContent );
673 
674  QgsVectorLayer *vl = mFilterModel->layer();
675  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
676  if ( canvas && vl && vl->geometryType() != QgsWkbTypes::NullGeometry )
677  {
678  menu->addAction( tr( "Zoom to Feature" ), this, SLOT( zoomToCurrentFeature() ) );
679  menu->addAction( tr( "Pan to Feature" ), this, SLOT( panToCurrentFeature() ) );
680  menu->addAction( tr( "Flash Feature" ), this, SLOT( flashCurrentFeature() ) );
681  }
682 
683  //add user-defined actions to context menu
684  QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( "Field" ) );
685  if ( !actions.isEmpty() )
686  {
687  QAction *a = menu->addAction( tr( "Run Layer Action" ) );
688  a->setEnabled( false );
689 
690  const auto constActions = actions;
691  for ( const QgsAction &action : constActions )
692  {
693  if ( !action.runable() )
694  continue;
695 
696  if ( vl && !vl->isEditable() && action.isEnabledOnlyWhenEditable() )
697  continue;
698 
699  QgsAttributeTableAction *a = new QgsAttributeTableAction( action.name(), this, action.id(), sourceIndex );
700  menu->addAction( action.name(), a, &QgsAttributeTableAction::execute );
701  }
702  }
703 
704  //add actions from QgsMapLayerActionRegistry to context menu
705  QList<QgsMapLayerAction *> registeredActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer );
706  if ( !registeredActions.isEmpty() )
707  {
708  //add a separator between user defined and standard actions
709  menu->addSeparator();
710 
711  const auto constRegisteredActions = registeredActions;
712  for ( QgsMapLayerAction *action : constRegisteredActions )
713  {
714  QgsAttributeTableMapLayerAction *a = new QgsAttributeTableMapLayerAction( action->text(), this, action, sourceIndex );
715  menu->addAction( action->text(), a, &QgsAttributeTableMapLayerAction::execute );
716  }
717  }
718 
719  menu->addSeparator();
720  QgsAttributeTableAction *a = new QgsAttributeTableAction( tr( "Open Form" ), this, QString(), sourceIndex );
721  menu->addAction( tr( "Open Form" ), a, &QgsAttributeTableAction::featureForm );
722 }
723 
724 
725 void QgsDualView::widgetWillShowContextMenu( QgsActionMenu *menu, const QModelIndex &atIndex )
726 {
727  emit showContextMenuExternally( menu, mFilterModel->rowToId( atIndex ) );
728 }
729 
730 
731 void QgsDualView::showViewHeaderMenu( QPoint point )
732 {
733  int col = mTableView->columnAt( point.x() );
734 
735  delete mHorizontalHeaderMenu;
736  mHorizontalHeaderMenu = new QMenu( this );
737 
738  QAction *hide = new QAction( tr( "&Hide Column" ), mHorizontalHeaderMenu );
739  connect( hide, &QAction::triggered, this, &QgsDualView::hideColumn );
740  hide->setData( col );
741  mHorizontalHeaderMenu->addAction( hide );
742  QAction *setWidth = new QAction( tr( "&Set Width…" ), mHorizontalHeaderMenu );
743  connect( setWidth, &QAction::triggered, this, &QgsDualView::resizeColumn );
744  setWidth->setData( col );
745  mHorizontalHeaderMenu->addAction( setWidth );
746  QAction *optimizeWidth = new QAction( tr( "&Autosize" ), mHorizontalHeaderMenu );
747  connect( optimizeWidth, &QAction::triggered, this, &QgsDualView::autosizeColumn );
748  optimizeWidth->setData( col );
749  mHorizontalHeaderMenu->addAction( optimizeWidth );
750 
751  mHorizontalHeaderMenu->addSeparator();
752  QAction *organize = new QAction( tr( "&Organize Columns…" ), mHorizontalHeaderMenu );
753  connect( organize, &QAction::triggered, this, &QgsDualView::organizeColumns );
754  mHorizontalHeaderMenu->addAction( organize );
755  QAction *sort = new QAction( tr( "&Sort…" ), mHorizontalHeaderMenu );
756  connect( sort, &QAction::triggered, this, &QgsDualView::modifySort );
757  mHorizontalHeaderMenu->addAction( sort );
758 
759  mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
760 }
761 
762 void QgsDualView::organizeColumns()
763 {
764  if ( !mLayer )
765  {
766  return;
767  }
768 
769  QgsOrganizeTableColumnsDialog dialog( mLayer, attributeTableConfig(), this );
770  if ( dialog.exec() == QDialog::Accepted )
771  {
772  QgsAttributeTableConfig config = dialog.config();
773  setAttributeTableConfig( config );
774  }
775 }
776 
777 void QgsDualView::tableColumnResized( int column, int width )
778 {
779  QgsAttributeTableConfig config = mConfig;
780  int sourceCol = config.mapVisibleColumnToIndex( column );
781  if ( sourceCol >= 0 && config.columnWidth( sourceCol ) != width )
782  {
783  config.setColumnWidth( sourceCol, width );
784  setAttributeTableConfig( config );
785  }
786 }
787 
788 void QgsDualView::hideColumn()
789 {
790  QAction *action = qobject_cast<QAction *>( sender() );
791  int col = action->data().toInt();
792  QgsAttributeTableConfig config = mConfig;
793  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
794  if ( sourceCol >= 0 )
795  {
796  config.setColumnHidden( sourceCol, true );
797  setAttributeTableConfig( config );
798  }
799 }
800 
801 void QgsDualView::resizeColumn()
802 {
803  QAction *action = qobject_cast<QAction *>( sender() );
804  int col = action->data().toInt();
805  if ( col < 0 )
806  return;
807 
808  QgsAttributeTableConfig config = mConfig;
809  int sourceCol = config.mapVisibleColumnToIndex( col );
810  if ( sourceCol >= 0 )
811  {
812  bool ok = false;
813  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
814  mTableView->columnWidth( col ),
815  0, 1000, 10, &ok );
816  if ( ok )
817  {
818  config.setColumnWidth( sourceCol, width );
819  setAttributeTableConfig( config );
820  }
821  }
822 }
823 
824 void QgsDualView::autosizeColumn()
825 {
826  QAction *action = qobject_cast<QAction *>( sender() );
827  int col = action->data().toInt();
828  mTableView->resizeColumnToContents( col );
829 }
830 
831 void QgsDualView::modifySort()
832 {
833  if ( !mLayer )
834  return;
835 
836  QgsAttributeTableConfig config = mConfig;
837 
838  QDialog orderByDlg;
839  orderByDlg.setWindowTitle( tr( "Configure Attribute Table Sort Order" ) );
840  QDialogButtonBox *dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
841  QGridLayout *layout = new QGridLayout();
842  connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
843  connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
844  orderByDlg.setLayout( layout );
845 
846  QGroupBox *sortingGroupBox = new QGroupBox();
847  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
848  sortingGroupBox->setCheckable( true );
849  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
850  layout->addWidget( sortingGroupBox );
851  sortingGroupBox->setLayout( new QGridLayout() );
852 
853  QgsExpressionBuilderWidget *expressionBuilder = new QgsExpressionBuilderWidget();
855  expressionBuilder->setExpressionContext( context );
856  expressionBuilder->setLayer( mLayer );
857  expressionBuilder->loadFieldNames();
858  expressionBuilder->loadRecent( QStringLiteral( "generic" ) );
859  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? mLayer->displayExpression() : sortExpression() );
860 
861  sortingGroupBox->layout()->addWidget( expressionBuilder );
862 
863  QCheckBox *cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
864  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
865  sortingGroupBox->layout()->addWidget( cbxSortAscending );
866 
867  layout->addWidget( dialogButtonBox );
868  if ( orderByDlg.exec() )
869  {
870  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
871  if ( sortingGroupBox->isChecked() )
872  {
873  setSortExpression( expressionBuilder->expressionText(), sortOrder );
874  config.setSortExpression( expressionBuilder->expressionText() );
875  config.setSortOrder( sortOrder );
876  }
877  else
878  {
879  setSortExpression( QString(), sortOrder );
880  config.setSortExpression( QString() );
881  }
882 
883  setAttributeTableConfig( config );
884  }
885 }
886 
887 void QgsDualView::zoomToCurrentFeature()
888 {
889  QModelIndex currentIndex = mTableView->currentIndex();
890  if ( !currentIndex.isValid() )
891  {
892  return;
893  }
894 
895  QgsFeatureIds ids;
896  ids.insert( mFilterModel->rowToId( currentIndex ) );
897  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
898  if ( canvas )
899  {
900  canvas->zoomToFeatureIds( mLayer, ids );
901  }
902 }
903 
904 void QgsDualView::panToCurrentFeature()
905 {
906  QModelIndex currentIndex = mTableView->currentIndex();
907  if ( !currentIndex.isValid() )
908  {
909  return;
910  }
911 
912  QgsFeatureIds ids;
913  ids.insert( mFilterModel->rowToId( currentIndex ) );
914  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
915  if ( canvas )
916  {
917  canvas->panToFeatureIds( mLayer, ids );
918  }
919 }
920 
921 void QgsDualView::flashCurrentFeature()
922 {
923  QModelIndex currentIndex = mTableView->currentIndex();
924  if ( !currentIndex.isValid() )
925  {
926  return;
927  }
928 
929  QgsFeatureIds ids;
930  ids.insert( mFilterModel->rowToId( currentIndex ) );
931  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
932  if ( canvas )
933  {
934  canvas->flashFeatureIds( mLayer, ids );
935  }
936 }
937 
938 void QgsDualView::rebuildFullLayerCache()
939 {
940  connect( mLayerCache, &QgsVectorLayerCache::progress, this, &QgsDualView::progress, Qt::UniqueConnection );
941  connect( mLayerCache, &QgsVectorLayerCache::finished, this, &QgsDualView::finished, Qt::UniqueConnection );
942 
943  mLayerCache->setFullCache( true );
944 }
945 
946 void QgsDualView::previewExpressionChanged( const QString &expression )
947 {
948  mLayer->setDisplayExpression( expression );
949 }
950 
951 void QgsDualView::onSortColumnChanged()
952 {
954  if ( cfg.sortExpression() != mFilterModel->sortExpression() ||
955  cfg.sortOrder() != mFilterModel->sortOrder() )
956  {
957  cfg.setSortExpression( mFilterModel->sortExpression() );
958  cfg.setSortOrder( mFilterModel->sortOrder() );
960  }
961 }
962 
963 void QgsDualView::sortByPreviewExpression()
964 {
965  Qt::SortOrder sortOrder = Qt::AscendingOrder;
966  if ( mFeatureListView->displayExpression() == sortExpression() )
967  {
968  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
969  }
970  setSortExpression( mFeatureListView->displayExpression(), sortOrder );
971 }
972 
973 void QgsDualView::updateSelectedFeatures()
974 {
975  QgsFeatureRequest r = mMasterModel->request();
977  return; // already requested all features
978 
979  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
980  mMasterModel->setRequest( r );
981  mMasterModel->loadLayer();
982  emit filterChanged();
983 }
984 
985 void QgsDualView::extentChanged()
986 {
987  QgsFeatureRequest r = mMasterModel->request();
988  if ( mFilterModel->mapCanvas() && ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) )
989  {
990  QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
991  r.setFilterRect( rect );
992  mMasterModel->setRequest( r );
993  mMasterModel->loadLayer();
994  }
995  emit filterChanged();
996 }
997 
998 void QgsDualView::featureFormAttributeChanged( const QString &attribute, const QVariant &value, bool attributeChanged )
999 {
1000  Q_UNUSED( attribute )
1001  Q_UNUSED( value )
1002  if ( attributeChanged )
1003  mFeatureListView->setCurrentFeatureEdited( true );
1004 }
1005 
1007 {
1008  mFilterModel->setFilteredFeatures( filteredFeatures );
1009 }
1010 
1012 {
1013  mMasterModel->setRequest( request );
1014 }
1015 
1017 {
1018  mTableView->setFeatureSelectionManager( featureSelectionManager );
1019  mFeatureListView->setFeatureSelectionManager( featureSelectionManager );
1020 
1021  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
1022  delete mFeatureSelectionManager;
1023 
1024  mFeatureSelectionManager = featureSelectionManager;
1025 }
1026 
1028 {
1029  mConfig = config;
1030  mConfig.update( mLayer->fields() );
1031  mLayer->setAttributeTableConfig( mConfig );
1032  mFilterModel->setAttributeTableConfig( mConfig );
1033  mTableView->setAttributeTableConfig( mConfig );
1034 }
1035 
1036 void QgsDualView::setSortExpression( const QString &sortExpression, Qt::SortOrder sortOrder )
1037 {
1038  if ( sortExpression.isNull() )
1039  mFilterModel->sort( -1 );
1040  else
1041  mFilterModel->sort( sortExpression, sortOrder );
1042 
1043  mConfig.setSortExpression( sortExpression );
1044  mConfig.setSortOrder( sortOrder );
1045  setAttributeTableConfig( mConfig );
1046 }
1047 
1049 {
1050  return mFilterModel->sortExpression();
1051 }
1052 
1054 {
1055  return mConfig;
1056 }
1057 
1058 void QgsDualView::progress( int i, bool &cancel )
1059 {
1060  if ( !mProgressDlg )
1061  {
1062  mProgressDlg = new QProgressDialog( tr( "Loading features…" ), tr( "Abort" ), 0, 0, this );
1063  mProgressDlg->setWindowTitle( tr( "Attribute Table" ) );
1064  mProgressDlg->setWindowModality( Qt::WindowModal );
1065  mProgressDlg->show();
1066  }
1067 
1068  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
1069  QCoreApplication::processEvents();
1070 
1071  cancel = mProgressDlg && mProgressDlg->wasCanceled();
1072 }
1073 
1074 void QgsDualView::finished()
1075 {
1076  delete mProgressDlg;
1077  mProgressDlg = nullptr;
1078 }
1079 
1080 /*
1081  * QgsAttributeTableAction
1082  */
1083 
1085 {
1086  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
1087 }
1088 
1090 {
1091  QgsFeatureIds editedIds;
1092  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
1093  mDualView->setCurrentEditSelection( editedIds );
1094  mDualView->setView( QgsDualView::AttributeEditor );
1095 }
1096 
1097 /*
1098  * QgsAttributeTableMapLayerAction
1099  */
1100 
1102 {
1103  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
1104 }
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
QgsFeatureId id
Definition: qgsfeature.h:64
QgsFeatureId rowToId(const QModelIndex &row)
Returns the feature id for a given model index.
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
A widget for customizing conditional formatting options.
void setFilterMode(QgsAttributeTableFilterModel::FilterMode filterMode)
Set the filter mode.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
void setSortExpression(const QString &sortExpression)
Set the sort expression used for sorting.
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
void update(const QgsFields &fields)
Update the configuration with the given fields.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table configuration to control which fields are shown, in which order they are show...
void init(QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request=QgsFeatureRequest(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), bool loadFeatures=true)
Has to be called to initialize the dual view.
void setExpressionText(const QString &text)
void willShowContextMenu(QMenu *menu, const QModelIndex &atIndex)
Emitted in order to provide a hook to add additional* menu entries to the context menu...
const Flags & flags() const
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:174
void filterExpressionSet(const QString &expression, QgsAttributeForm::FilterType type)
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()
void currentEditSelectionProgressChanged(int progress, int count)
Emitted whenever the current edit selection has been changed.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QString sortExpression() const
Gets the expression used for sorting the table and feature list.
This class contains context information for attribute editor widgets.
void setLayer(QgsVectorLayer *layer)
Sets layer in order to get the fields and values.
bool save()
Save all the values from the editors to the layer.
ViewMode
The view modes, in which this widget can present information.
Definition: qgsdualview.h:53
void willShowContextMenu(QgsActionMenu *menu, const QModelIndex &atIndex)
Emitted when the context menu is created to add the specific actions to it.
void setLayer(QgsVectorLayer *layer)
Sets the vector layer associated with the widget.
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.
~QgsDualView() override
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 map is zoomed to contained the feature bounding-box.
Definition: qgsdualview.h:76
Multi edit mode, for editing fields of multiple features at once.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
Show only visible features (depends on the map canvas)
void setCurrentEditSelection(const QgsFeatureIds &fids)
Set the current edit selection in the AttributeEditor mode.
int mapVisibleColumnToIndex(int visibleColumn) const
Maps a visible column index to its original column index.
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:75
void hideEvent(QHideEvent *event) override
void setView(ViewMode view)
Change the current view mode.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs...
virtual void setFilteredFeatures(const QgsFeatureIds &ids)
Specify a list of features, which the filter will accept.
static QgsShortcutsManager * shortcutsManager()
Returns the global shortcuts manager, used for managing a QAction and QShortcut sequences.
Definition: qgsgui.cpp:82
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:48
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
Definition: qgsdualview.h:66
Shows a list of features and renders a edit button next to each feature.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
void editFirstFeature()
editFirstFeature will try to edit the first feature of the list
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 editNextFeature()
editNextFeature will try to edit next feature of the list
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...
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)
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:72
ViewMode view() const
Returns the current view mode.
QgsAttributeTableConfig attributeTableConfig() const
The config used for the attribute table.
Utility class that encapsulates an action based on vector attributes.
Definition: qgsaction.h:35
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void progress(int i, bool &cancel)
When filling the cache, this signal gets emitted periodically to notify about the progress and to be ...
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
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:167
void refreshFeature()
reload current feature
void displayExpressionChanged(const QString &expression)
Emitted whenever the display expression is successfully changed.
void filterChanged()
Emitted whenever the filter changes.
void editPreviousFeature()
editPreviousFeature will try to edit previous feature of the list
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
void loadFieldNames()
Loads all the field names from the layer.
Show only features which have unsaved changes.
const QgsFeatureRequest & request() const
Gets the the feature request.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
Fast access to features using their ID.
void cancelProgress()
Cancel the progress dialog (if any)
void widgetValueChanged(const QString &attribute, const QVariant &value, bool attributeChanged)
Notifies about changes of attributes.
void setMode(QgsAttributeEditorContext::Mode mode)
Sets the current mode of the form.
FeatureListBrowsingAction
Action on the map canvas when browsing the list of features.
Definition: qgsdualview.h:72
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context for the widget.
QShortcut * shortcutByName(const QString &name) const
Returns a shortcut by its name, or nullptr if nothing found.
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 setEnumValue(const QString &key, const T &value, const Section section=NoSection)
Set the value of a setting based on an enum.
Definition: qgssettings.h:296
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:131
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:227
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.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
void setFullCache(bool fullCache)
This enables or disables full caching.
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Sort by the given column using the given order.
void setColumnHidden(int column, bool hidden)
Sets whether the specified column should be hidden.
Single edit mode, for editing a single feature.
No action is done.
Definition: qgsdualview.h:74
void panToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids, bool alwaysRecenter=true)
Centers canvas extent to feature ids.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:436
QgsMapCanvas * mapCanvas() const
Returns the map canvas.
void displayExpressionChanged(const QString &expression)
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.
T enumValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on an enum.
Definition: qgssettings.h:244
void setExpressionText(const QString &expression)
Sets the expression string for the widget.
void setSortByDisplayExpression(bool sortByDisplayExpression)
Sort this model by its display expression.
void setFilteredFeatures(const QgsFeatureIds &filteredFeatures)
Set a list of currently visible features.
void editLastFeature()
editLastFeature will try to edit the last feature of the list
This is a container for configuration of the attribute table.
Qt::SortOrder sortOrder() const
Gets the sort order.
Form values are used for searching/filtering the layer.
A QScrollArea subclass with improved scrolling behavior.
Definition: qgsscrollarea.h:41
Geometry is not required. It may still be returned if e.g. required for a filter condition.
void setMultiEditEnabled(bool enabled)
Sets whether multi edit mode is enabled.
Is an interface class to abstract feature selection handling.
void currentEditSelectionChanged(QgsFeature &feat)
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)
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:92
void finished()
When filling the cache, this signal gets emitted once the cache is fully initialized.
void extentsChanged()
Emitted when the extents of the map change.
A generic dialog for building expression strings.
An action which can run on map layers.
int featureCount()
Returns the number of features on the layer.
void formModeChanged(QgsAttributeEditorContext::Mode mode)
Emitted when the form changes mode.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
The map is panned to the center of the feature bounding-box.
Definition: qgsdualview.h:75
void rulesUpdated(const QString &fieldName)
Emitted when the conditional styling rules are updated.
void modeChanged(QgsAttributeEditorContext::Mode mode)
Emitted when the form changes mode.