QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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  // disable the browsing auto pan/scale if the list only shows visible items
305  switch ( filterMode )
306  {
308  setBrowsingAutoPanScaleAllowed( false );
309  break;
310 
315  setBrowsingAutoPanScaleAllowed( true );
316  break;
317  }
318 
319  //update filter model
320  mFilterModel->setFilterMode( filterMode );
321  emit filterChanged();
322 }
323 
324 void QgsDualView::setSelectedOnTop( bool selectedOnTop )
325 {
326  mFilterModel->setSelectedOnTop( selectedOnTop );
327 }
328 
329 void QgsDualView::initLayerCache( bool cacheGeometry )
330 {
331  // Initialize the cache
332  QgsSettings settings;
333  int cacheSize = settings.value( QStringLiteral( "qgis/attributeTableRowCache" ), "10000" ).toInt();
334  mLayerCache = new QgsVectorLayerCache( mLayer, cacheSize, this );
335  mLayerCache->setCacheGeometry( cacheGeometry );
336  if ( 0 == cacheSize || 0 == ( QgsVectorDataProvider::SelectAtId & mLayer->dataProvider()->capabilities() ) )
337  {
338  connect( mLayerCache, &QgsVectorLayerCache::invalidated, this, &QgsDualView::rebuildFullLayerCache );
339  rebuildFullLayerCache();
340  }
341 }
342 
343 void QgsDualView::initModels( QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, bool loadFeatures )
344 {
345  delete mFeatureListModel;
346  delete mFilterModel;
347  delete mMasterModel;
348 
349  mMasterModel = new QgsAttributeTableModel( mLayerCache, this );
350  mMasterModel->setRequest( request );
351  mMasterModel->setEditorContext( mEditorContext );
352  mMasterModel->setExtraColumns( 1 ); // Add one extra column which we can "abuse" as an action column
353 
354  connect( mMasterModel, &QgsAttributeTableModel::progress, this, &QgsDualView::progress );
355  connect( mMasterModel, &QgsAttributeTableModel::finished, this, &QgsDualView::finished );
356 
358 
359  if ( loadFeatures )
360  mMasterModel->loadLayer();
361 
362  mFilterModel = new QgsAttributeTableFilterModel( mapCanvas, mMasterModel, mMasterModel );
363 
364  // The following connections to invalidate() are necessary to keep the filter model in sync
365  // see regression https://github.com/qgis/QGIS/issues/23890
366  connect( mMasterModel, &QgsAttributeTableModel::rowsRemoved, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
367  connect( mMasterModel, &QgsAttributeTableModel::rowsInserted, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
368 
370 
371  mFeatureListModel = new QgsFeatureListModel( mFilterModel, mFilterModel );
372  mFeatureListModel->setSortByDisplayExpression( true );
373 }
374 
375 void QgsDualView::restoreRecentDisplayExpressions()
376 {
377  const QVariantList previewExpressions = mLayer->customProperty( QStringLiteral( "dualview/previewExpressions" ) ).toList();
378 
379  for ( const QVariant &previewExpression : previewExpressions )
380  insertRecentlyUsedDisplayExpression( previewExpression.toString() );
381 }
382 
383 void QgsDualView::saveRecentDisplayExpressions() const
384 {
385  if ( ! mLayer )
386  {
387  return;
388  }
389  QList<QAction *> actions = mFeatureListPreviewButton->actions();
390 
391  // Remove existing same action
392  int index = actions.indexOf( mLastDisplayExpressionAction );
393  if ( index != -1 )
394  {
395  QVariantList previewExpressions;
396  for ( ; index < actions.length(); ++index )
397  {
398  QAction *action = actions.at( index );
399  previewExpressions << action->property( "previewExpression" );
400  }
401 
402  mLayer->setCustomProperty( QStringLiteral( "dualview/previewExpressions" ), previewExpressions );
403  }
404 }
405 
406 void QgsDualView::setDisplayExpression( const QString &expression )
407 {
408  mDisplayExpression = expression;
409  insertRecentlyUsedDisplayExpression( expression );
410 }
411 
412 void QgsDualView::insertRecentlyUsedDisplayExpression( const QString &expression )
413 {
414  QList<QAction *> actions = mFeatureListPreviewButton->actions();
415 
416  // Remove existing same action
417  int index = actions.indexOf( mLastDisplayExpressionAction );
418  if ( index != -1 )
419  {
420  for ( int i = 0; index + i < actions.length(); ++i )
421  {
422  QAction *action = actions.at( index );
423  if ( action->text() == expression || i >= 9 )
424  {
425  if ( action == mLastDisplayExpressionAction )
426  mLastDisplayExpressionAction = nullptr;
427  mFeatureListPreviewButton->removeAction( action );
428  }
429  else
430  {
431  if ( !mLastDisplayExpressionAction )
432  mLastDisplayExpressionAction = action;
433  }
434  }
435  }
436 
437  QString name = expression;
438  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) );
439  if ( expression.startsWith( QLatin1String( "COALESCE( \"" ) ) && expression.endsWith( QLatin1String( ", '<NULL>' )" ) ) )
440  {
441  name = expression.mid( 11, expression.length() - 24 ); // Numbers calculated from the COALESCE / <NULL> parts
442 
443  int fieldIndex = mLayer->fields().indexOf( name );
444  if ( fieldIndex != -1 )
445  {
446  name = mLayer->attributeDisplayName( fieldIndex );
447  icon = mLayer->fields().iconForField( fieldIndex );
448  }
449  else
450  {
451  name = expression;
452  }
453  }
454 
455  QAction *previewAction = new QAction( icon, name, mFeatureListPreviewButton );
456  previewAction->setProperty( "previewExpression", expression );
457  connect( previewAction, &QAction::triggered, this, [expression, this]( bool )
458  {
459  setDisplayExpression( expression );
460  mFeatureListPreviewButton->setText( expression );
461  }
462  );
463 
464  mFeatureListPreviewButton->insertAction( mLastDisplayExpressionAction, previewAction );
465  mLastDisplayExpressionAction = previewAction;
466 }
467 
468 void QgsDualView::updateEditSelectionProgress( int progress, int count )
469 {
470  mProgressCount->setText( QStringLiteral( "%1 / %2" ).arg( progress + 1 ).arg( count ) );
471  mPreviousFeatureButton->setEnabled( progress > 0 );
472  mNextFeatureButton->setEnabled( progress + 1 < count );
473  mFirstFeatureButton->setEnabled( progress > 0 );
474  mLastFeatureButton->setEnabled( progress + 1 < count );
475 }
476 
477 void QgsDualView::panOrZoomToFeature( const QgsFeatureIds &featureset )
478 {
479  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
480  if ( canvas && view() == AttributeEditor && featureset != mLastFeatureSet )
481  {
482  if ( mBrowsingAutoPanScaleAllowed )
483  {
484  if ( mAutoPanButton->isChecked() )
485  QTimer::singleShot( 0, this, [ = ]()
486  {
487  canvas->panToFeatureIds( mLayer, featureset, false );
488  } );
489  else if ( mAutoZoomButton->isChecked() )
490  QTimer::singleShot( 0, this, [ = ]()
491  {
492  canvas->zoomToFeatureIds( mLayer, featureset );
493  } );
494  }
495  if ( mFlashButton->isChecked() )
496  QTimer::singleShot( 0, this, [ = ]()
497  {
498  canvas->flashFeatureIds( mLayer, featureset );
499  } );
500  mLastFeatureSet = featureset;
501  }
502 }
503 
504 void QgsDualView::setBrowsingAutoPanScaleAllowed( bool allowed )
505 {
506  if ( mBrowsingAutoPanScaleAllowed == allowed )
507  return;
508 
509  mBrowsingAutoPanScaleAllowed = allowed;
510 
511  mAutoPanButton->setEnabled( allowed );
512  mAutoZoomButton->setEnabled( allowed );
513 
514  QString disabledHint = tr( "(disabled when attribute table only shows features visible in the current map canvas extent)" );
515 
516  mAutoPanButton->setToolTip( tr( "Automatically pan to the current feature" ) + ( allowed ? QString() : QString( ' ' ) + disabledHint ) );
517  mAutoZoomButton->setToolTip( tr( "Automatically zoom to the current feature" ) + ( allowed ? QString() : QString( ' ' ) + disabledHint ) );
518 }
519 
520 void QgsDualView::panZoomGroupButtonToggled( QAbstractButton *button, bool checked )
521 {
522  if ( button == mAutoPanButton && checked )
523  {
524  QgsSettings().setEnumValue( QStringLiteral( "/qgis/attributeTable/featureListBrowsingAction" ), PanToFeature );
525  mAutoZoomButton->setChecked( false );
526  }
527  else if ( button == mAutoZoomButton && checked )
528  {
529  QgsSettings().setEnumValue( QStringLiteral( "/qgis/attributeTable/featureListBrowsingAction" ), ZoomToFeature );
530  mAutoPanButton->setChecked( false );
531  }
532  else
533  {
534  QgsSettings().setEnumValue( QStringLiteral( "/qgis/attributeTable/featureListBrowsingAction" ), NoAction );
535  }
536 
537  if ( checked )
538  panOrZoomToFeature( mFeatureListView->currentEditSelection() );
539 }
540 
541 void QgsDualView::flashButtonClicked( bool clicked )
542 {
543  QgsSettings().setValue( QStringLiteral( "/qgis/attributeTable/featureListHighlightFeature" ), clicked );
544  if ( !clicked )
545  return;
546 
547  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
548 
549  if ( canvas )
550  canvas->flashFeatureIds( mLayer, mFeatureListView->currentEditSelection() );
551 }
552 
553 void QgsDualView::featureListAboutToChangeEditSelection( bool &ok )
554 {
555  if ( mLayer->isEditable() && !mAttributeForm->save() )
556  ok = false;
557 }
558 
559 void QgsDualView::featureListCurrentEditSelectionChanged( const QgsFeature &feat )
560 {
561  if ( !mAttributeForm )
562  {
563  mTempAttributeFormFeature = feat;
564  }
565  else if ( !mLayer->isEditable() || mAttributeForm->save() )
566  {
567  mAttributeForm->setFeature( feat );
568  QgsFeatureIds featureset;
569  featureset << feat.id();
570  setCurrentEditSelection( featureset );
571 
572  panOrZoomToFeature( featureset );
573 
574  }
575  else
576  {
577  // Couldn't save feature
578  }
579 }
580 
582 {
583  mFeatureListView->setCurrentFeatureEdited( false );
584  mFeatureListView->setEditSelection( fids );
585 }
586 
588 {
589  return mAttributeForm->save();
590 }
591 
593 {
594  mConditionalFormatWidgetStack->setVisible( !mConditionalFormatWidgetStack->isVisible() );
595 }
596 
598 {
599  if ( enabled )
601 
603 }
604 
605 void QgsDualView::toggleSearchMode( bool enabled )
606 {
607  if ( enabled )
608  {
611  }
612  else
613  {
615  }
616 }
617 
618 void QgsDualView::previewExpressionBuilder()
619 {
620  // Show expression builder
622 
623  QgsExpressionBuilderDialog dlg( mLayer, mFeatureListView->displayExpression(), this, QStringLiteral( "generic" ), context );
624  dlg.setWindowTitle( tr( "Expression Based Preview" ) );
625  dlg.setExpressionText( mFeatureListView->displayExpression() );
626 
627  if ( dlg.exec() == QDialog::Accepted )
628  {
629  mFeatureListView->setDisplayExpression( dlg.expressionText() );
630  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
631  mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
632  }
633 
634  setDisplayExpression( mFeatureListView->displayExpression() );
635 }
636 
637 void QgsDualView::previewColumnChanged( QAction *previewAction, const QString &expression )
638 {
639  if ( !mFeatureListView->setDisplayExpression( QStringLiteral( "COALESCE( \"%1\", '<NULL>' )" ).arg( expression ) ) )
640  {
641  QMessageBox::warning( this,
642  tr( "Column Preview" ),
643  tr( "Could not set column '%1' as preview column.\nParser error:\n%2" )
644  .arg( previewAction->text(), mFeatureListView->parserErrorString() )
645  );
646  }
647  else
648  {
649  mFeatureListPreviewButton->setText( previewAction->text() );
650  mFeatureListPreviewButton->setIcon( previewAction->icon() );
651  mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
652  }
653 
654  setDisplayExpression( mFeatureListView->displayExpression() );
655 }
656 
658 {
659  return mMasterModel->rowCount();
660 }
661 
663 {
664  return mFilterModel->rowCount();
665 }
666 
668 {
669  QAction *action = qobject_cast<QAction *>( sender() );
670 
671  if ( action && action->data().isValid() && action->data().canConvert<QModelIndex>() )
672  {
673  QModelIndex index = action->data().toModelIndex();
674  QVariant var = masterModel()->data( index, Qt::DisplayRole );
675  QApplication::clipboard()->setText( var.toString() );
676  }
677 }
678 
680 {
681  if ( mProgressDlg )
682  mProgressDlg->cancel();
683 }
684 
685 void QgsDualView::hideEvent( QHideEvent *event )
686 {
687  Q_UNUSED( event )
688  saveRecentDisplayExpressions();
689 }
690 
691 void QgsDualView::viewWillShowContextMenu( QMenu *menu, const QModelIndex &atIndex )
692 {
693  if ( !menu )
694  {
695  return;
696  }
697 
698  QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
699 
700  QAction *copyContentAction = new QAction( tr( "Copy Cell Content" ), this );
701  copyContentAction->setData( QVariant::fromValue<QModelIndex>( sourceIndex ) );
702  menu->addAction( copyContentAction );
703  connect( copyContentAction, &QAction::triggered, this, &QgsDualView::copyCellContent );
704 
705  QgsVectorLayer *vl = mFilterModel->layer();
706  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
707  if ( canvas && vl && vl->geometryType() != QgsWkbTypes::NullGeometry )
708  {
709  menu->addAction( tr( "Zoom to Feature" ), this, SLOT( zoomToCurrentFeature() ) );
710  menu->addAction( tr( "Pan to Feature" ), this, SLOT( panToCurrentFeature() ) );
711  menu->addAction( tr( "Flash Feature" ), this, SLOT( flashCurrentFeature() ) );
712  }
713 
714  //add user-defined actions to context menu
715  QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( "Field" ) );
716  if ( !actions.isEmpty() )
717  {
718  QAction *a = menu->addAction( tr( "Run Layer Action" ) );
719  a->setEnabled( false );
720 
721  const auto constActions = actions;
722  for ( const QgsAction &action : constActions )
723  {
724  if ( !action.runable() )
725  continue;
726 
727  if ( vl && !vl->isEditable() && action.isEnabledOnlyWhenEditable() )
728  continue;
729 
730  QgsAttributeTableAction *a = new QgsAttributeTableAction( action.name(), this, action.id(), sourceIndex );
731  menu->addAction( action.name(), a, &QgsAttributeTableAction::execute );
732  }
733  }
734  QModelIndex rowSourceIndex = mFilterModel->fidToIndex( mFilterModel->rowToId( atIndex ) );
735  if ( ! rowSourceIndex.isValid() )
736  {
737  return;
738  }
739  //add actions from QgsMapLayerActionRegistry to context menu
740  QList<QgsMapLayerAction *> registeredActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer, QgsMapLayerAction::Layer | QgsMapLayerAction::SingleFeature );
741  if ( !registeredActions.isEmpty() )
742  {
743  //add a separator between user defined and standard actions
744  menu->addSeparator();
745 
746  const auto constRegisteredActions = registeredActions;
747  for ( QgsMapLayerAction *action : constRegisteredActions )
748  {
749  QgsAttributeTableMapLayerAction *a = new QgsAttributeTableMapLayerAction( action->text(), this, action, rowSourceIndex );
750  menu->addAction( action->text(), a, &QgsAttributeTableMapLayerAction::execute );
751  }
752  }
753 
754  // entries for multiple features layer actions
755  // only show if the context menu is shown over a selected row
756  QgsFeatureId currentFid = masterModel()->rowToId( sourceIndex.row() );
757  if ( mLayer->selectedFeatureCount() > 1 && mLayer->selectedFeatureIds().contains( currentFid ) )
758  {
759  const QList<QgsMapLayerAction *> constRegisteredActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer, QgsMapLayerAction::MultipleFeatures );
760  if ( !constRegisteredActions.isEmpty() )
761  {
762  menu->addSeparator();
763  QAction *action = menu->addAction( tr( "Actions on Selection (%1)" ).arg( mLayer->selectedFeatureCount() ) );
764  action->setEnabled( false );
765 
766  for ( QgsMapLayerAction *action : constRegisteredActions )
767  {
768  menu->addAction( action->text(), action, [ = ]() {action->triggerForFeatures( mLayer, mLayer->selectedFeatures() );} );
769  }
770  }
771  }
772 
773  menu->addSeparator();
774  QgsAttributeTableAction *a = new QgsAttributeTableAction( tr( "Open Form" ), this, QString(), rowSourceIndex );
775  menu->addAction( tr( "Open Form" ), a, &QgsAttributeTableAction::featureForm );
776 }
777 
778 
779 void QgsDualView::widgetWillShowContextMenu( QgsActionMenu *menu, const QModelIndex &atIndex )
780 {
781  emit showContextMenuExternally( menu, mFilterModel->rowToId( atIndex ) );
782 }
783 
784 
785 void QgsDualView::showViewHeaderMenu( QPoint point )
786 {
787  int col = mTableView->columnAt( point.x() );
788 
789  delete mHorizontalHeaderMenu;
790  mHorizontalHeaderMenu = new QMenu( this );
791 
792  QAction *hide = new QAction( tr( "&Hide Column" ), mHorizontalHeaderMenu );
793  connect( hide, &QAction::triggered, this, &QgsDualView::hideColumn );
794  hide->setData( col );
795  mHorizontalHeaderMenu->addAction( hide );
796  QAction *setWidth = new QAction( tr( "&Set Width…" ), mHorizontalHeaderMenu );
797  connect( setWidth, &QAction::triggered, this, &QgsDualView::resizeColumn );
798  setWidth->setData( col );
799  mHorizontalHeaderMenu->addAction( setWidth );
800  QAction *optimizeWidth = new QAction( tr( "&Autosize" ), mHorizontalHeaderMenu );
801  connect( optimizeWidth, &QAction::triggered, this, &QgsDualView::autosizeColumn );
802  optimizeWidth->setData( col );
803  mHorizontalHeaderMenu->addAction( optimizeWidth );
804 
805  mHorizontalHeaderMenu->addSeparator();
806  QAction *organize = new QAction( tr( "&Organize Columns…" ), mHorizontalHeaderMenu );
807  connect( organize, &QAction::triggered, this, &QgsDualView::organizeColumns );
808  mHorizontalHeaderMenu->addAction( organize );
809  QAction *sort = new QAction( tr( "&Sort…" ), mHorizontalHeaderMenu );
810  connect( sort, &QAction::triggered, this, &QgsDualView::modifySort );
811  mHorizontalHeaderMenu->addAction( sort );
812 
813  mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
814 }
815 
816 void QgsDualView::organizeColumns()
817 {
818  if ( !mLayer )
819  {
820  return;
821  }
822 
823  QgsOrganizeTableColumnsDialog dialog( mLayer, attributeTableConfig(), this );
824  if ( dialog.exec() == QDialog::Accepted )
825  {
826  QgsAttributeTableConfig config = dialog.config();
827  setAttributeTableConfig( config );
828  }
829 }
830 
831 void QgsDualView::tableColumnResized( int column, int width )
832 {
833  QgsAttributeTableConfig config = mConfig;
834  int sourceCol = config.mapVisibleColumnToIndex( column );
835  if ( sourceCol >= 0 && config.columnWidth( sourceCol ) != width )
836  {
837  config.setColumnWidth( sourceCol, width );
838  setAttributeTableConfig( config );
839  }
840 }
841 
842 void QgsDualView::hideColumn()
843 {
844  QAction *action = qobject_cast<QAction *>( sender() );
845  int col = action->data().toInt();
846  QgsAttributeTableConfig config = mConfig;
847  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
848  if ( sourceCol >= 0 )
849  {
850  config.setColumnHidden( sourceCol, true );
851  setAttributeTableConfig( config );
852  }
853 }
854 
855 void QgsDualView::resizeColumn()
856 {
857  QAction *action = qobject_cast<QAction *>( sender() );
858  int col = action->data().toInt();
859  if ( col < 0 )
860  return;
861 
862  QgsAttributeTableConfig config = mConfig;
863  int sourceCol = config.mapVisibleColumnToIndex( col );
864  if ( sourceCol >= 0 )
865  {
866  bool ok = false;
867  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
868  mTableView->columnWidth( col ),
869  0, 1000, 10, &ok );
870  if ( ok )
871  {
872  config.setColumnWidth( sourceCol, width );
873  setAttributeTableConfig( config );
874  }
875  }
876 }
877 
878 void QgsDualView::autosizeColumn()
879 {
880  QAction *action = qobject_cast<QAction *>( sender() );
881  int col = action->data().toInt();
882  mTableView->resizeColumnToContents( col );
883 }
884 
885 void QgsDualView::modifySort()
886 {
887  if ( !mLayer )
888  return;
889 
890  QgsAttributeTableConfig config = mConfig;
891 
892  QDialog orderByDlg;
893  orderByDlg.setWindowTitle( tr( "Configure Attribute Table Sort Order" ) );
894  QDialogButtonBox *dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
895  QGridLayout *layout = new QGridLayout();
896  connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
897  connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
898  orderByDlg.setLayout( layout );
899 
900  QGroupBox *sortingGroupBox = new QGroupBox();
901  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
902  sortingGroupBox->setCheckable( true );
903  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
904  layout->addWidget( sortingGroupBox );
905  sortingGroupBox->setLayout( new QGridLayout() );
906 
907  QgsExpressionBuilderWidget *expressionBuilder = new QgsExpressionBuilderWidget();
909  expressionBuilder->setExpressionContext( context );
910  expressionBuilder->setLayer( mLayer );
911  expressionBuilder->loadFieldNames();
912  expressionBuilder->loadRecent( QStringLiteral( "generic" ) );
913  expressionBuilder->loadUserExpressions( );
914  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? mLayer->displayExpression() : sortExpression() );
915 
916  sortingGroupBox->layout()->addWidget( expressionBuilder );
917 
918  QCheckBox *cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
919  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
920  sortingGroupBox->layout()->addWidget( cbxSortAscending );
921 
922  layout->addWidget( dialogButtonBox );
923  if ( orderByDlg.exec() )
924  {
925  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
926  if ( sortingGroupBox->isChecked() )
927  {
928  setSortExpression( expressionBuilder->expressionText(), sortOrder );
929  config.setSortExpression( expressionBuilder->expressionText() );
930  config.setSortOrder( sortOrder );
931  }
932  else
933  {
934  setSortExpression( QString(), sortOrder );
935  config.setSortExpression( QString() );
936  }
937 
938  setAttributeTableConfig( config );
939  }
940 }
941 
942 void QgsDualView::zoomToCurrentFeature()
943 {
944  QModelIndex currentIndex = mTableView->currentIndex();
945  if ( !currentIndex.isValid() )
946  {
947  return;
948  }
949 
950  QgsFeatureIds ids;
951  ids.insert( mFilterModel->rowToId( currentIndex ) );
952  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
953  if ( canvas )
954  {
955  canvas->zoomToFeatureIds( mLayer, ids );
956  }
957 }
958 
959 void QgsDualView::panToCurrentFeature()
960 {
961  QModelIndex currentIndex = mTableView->currentIndex();
962  if ( !currentIndex.isValid() )
963  {
964  return;
965  }
966 
967  QgsFeatureIds ids;
968  ids.insert( mFilterModel->rowToId( currentIndex ) );
969  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
970  if ( canvas )
971  {
972  canvas->panToFeatureIds( mLayer, ids );
973  }
974 }
975 
976 void QgsDualView::flashCurrentFeature()
977 {
978  QModelIndex currentIndex = mTableView->currentIndex();
979  if ( !currentIndex.isValid() )
980  {
981  return;
982  }
983 
984  QgsFeatureIds ids;
985  ids.insert( mFilterModel->rowToId( currentIndex ) );
986  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
987  if ( canvas )
988  {
989  canvas->flashFeatureIds( mLayer, ids );
990  }
991 }
992 
993 void QgsDualView::rebuildFullLayerCache()
994 {
995  connect( mLayerCache, &QgsVectorLayerCache::progress, this, &QgsDualView::progress, Qt::UniqueConnection );
996  connect( mLayerCache, &QgsVectorLayerCache::finished, this, &QgsDualView::finished, Qt::UniqueConnection );
997 
998  mLayerCache->setFullCache( true );
999 }
1000 
1001 void QgsDualView::previewExpressionChanged( const QString &expression )
1002 {
1003  mLayer->setDisplayExpression( expression );
1004 }
1005 
1006 void QgsDualView::onSortColumnChanged()
1007 {
1009  if ( cfg.sortExpression() != mFilterModel->sortExpression() ||
1010  cfg.sortOrder() != mFilterModel->sortOrder() )
1011  {
1012  cfg.setSortExpression( mFilterModel->sortExpression() );
1013  cfg.setSortOrder( mFilterModel->sortOrder() );
1014  setAttributeTableConfig( cfg );
1015  }
1016 }
1017 
1018 void QgsDualView::sortByPreviewExpression()
1019 {
1020  Qt::SortOrder sortOrder = Qt::AscendingOrder;
1021  if ( mFeatureListView->displayExpression() == sortExpression() )
1022  {
1023  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
1024  }
1025  setSortExpression( mFeatureListView->displayExpression(), sortOrder );
1026 }
1027 
1028 void QgsDualView::updateSelectedFeatures()
1029 {
1030  QgsFeatureRequest r = mMasterModel->request();
1032  return; // already requested all features
1033 
1034  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
1035  mMasterModel->setRequest( r );
1036  mMasterModel->loadLayer();
1037  emit filterChanged();
1038 }
1039 
1040 void QgsDualView::extentChanged()
1041 {
1042  QgsFeatureRequest r = mMasterModel->request();
1043  if ( mFilterModel->mapCanvas() && ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) )
1044  {
1045  QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
1046  r.setFilterRect( rect );
1047  mMasterModel->setRequest( r );
1048  mMasterModel->loadLayer();
1049  }
1050  emit filterChanged();
1051 }
1052 
1053 void QgsDualView::featureFormAttributeChanged( const QString &attribute, const QVariant &value, bool attributeChanged )
1054 {
1055  Q_UNUSED( attribute )
1056  Q_UNUSED( value )
1057  if ( attributeChanged )
1058  mFeatureListView->setCurrentFeatureEdited( true );
1059 }
1060 
1062 {
1063  mFilterModel->setFilteredFeatures( filteredFeatures );
1064 }
1065 
1067 {
1068  mMasterModel->setRequest( request );
1069 }
1070 
1072 {
1073  mTableView->setFeatureSelectionManager( featureSelectionManager );
1074  mFeatureListView->setFeatureSelectionManager( featureSelectionManager );
1075 
1076  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
1077  delete mFeatureSelectionManager;
1078 
1079  mFeatureSelectionManager = featureSelectionManager;
1080 }
1081 
1083 {
1084  mConfig = config;
1085  mConfig.update( mLayer->fields() );
1086  mLayer->setAttributeTableConfig( mConfig );
1087  mFilterModel->setAttributeTableConfig( mConfig );
1088  mTableView->setAttributeTableConfig( mConfig );
1089 }
1090 
1091 void QgsDualView::setSortExpression( const QString &sortExpression, Qt::SortOrder sortOrder )
1092 {
1093  if ( sortExpression.isNull() )
1094  mFilterModel->sort( -1 );
1095  else
1096  mFilterModel->sort( sortExpression, sortOrder );
1097 
1098  mConfig.setSortExpression( sortExpression );
1099  mConfig.setSortOrder( sortOrder );
1100  setAttributeTableConfig( mConfig );
1101 }
1102 
1104 {
1105  return mFilterModel->sortExpression();
1106 }
1107 
1109 {
1110  return mConfig;
1111 }
1112 
1113 void QgsDualView::progress( int i, bool &cancel )
1114 {
1115  if ( !mProgressDlg )
1116  {
1117  mProgressDlg = new QProgressDialog( tr( "Loading features…" ), tr( "Abort" ), 0, 0, this );
1118  mProgressDlg->setWindowTitle( tr( "Attribute Table" ) );
1119  mProgressDlg->setWindowModality( Qt::WindowModal );
1120  mProgressDlg->show();
1121  }
1122 
1123  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
1124  QCoreApplication::processEvents();
1125 
1126  cancel = mProgressDlg && mProgressDlg->wasCanceled();
1127 }
1128 
1129 void QgsDualView::finished()
1130 {
1131  delete mProgressDlg;
1132  mProgressDlg = nullptr;
1133 }
1134 
1135 /*
1136  * QgsAttributeTableAction
1137  */
1138 
1140 {
1141  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
1142 }
1143 
1145 {
1146  QgsFeatureIds editedIds;
1147  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
1148  mDualView->setCurrentEditSelection( editedIds );
1149  mDualView->setView( QgsDualView::AttributeEditor );
1150 }
1151 
1152 /*
1153  * QgsAttributeTableMapLayerAction
1154  */
1155 
1157 {
1158  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
1159 }
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:173
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 setLayer(QgsVectorLayer *layer)
Sets the vector layer associated with the widget.
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
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.
Q_INVOKABLE 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: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
void loadRecent(const QString &collection=QStringLiteral("generic"))
Loads the recent expressions from the given collection.
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:83
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: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...
void aboutToChangeEditSelection(bool &ok)
This class is a menu that is populated automatically with the actions defined for a given layer...
Definition: qgsactionmenu.h:37
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:73
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:166
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:49
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:297
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:130
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:262
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:245
QgsFeatureId rowToId(int row) const
Maps row to feature id.
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:93
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.
void loadUserExpressions()
Loads the user expressions.
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.
QModelIndex fidToIndex(QgsFeatureId fid) override
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.