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