QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsdualview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdualview.cpp
3  --------------------------------------
4  Date : 10.2.2013
5  Copyright : (C) 2013 Matthias Kuhn
6  Email : matthias at opengis dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsapplication.h"
17 #include "qgsactionmanager.h"
18 #include "qgsattributetablemodel.h"
19 #include "qgsdualview.h"
21 #include "qgsfeaturelistmodel.h"
23 #include "qgsmapcanvas.h"
25 #include "qgsmessagelog.h"
26 #include "qgsvectordataprovider.h"
27 #include "qgsvectorlayercache.h"
30 #include "qgssettings.h"
31 #include "qgsscrollarea.h"
32 #include "qgsgui.h"
33 
34 #include <QClipboard>
35 #include <QDialog>
36 #include <QMenu>
37 #include <QMessageBox>
38 #include <QProgressDialog>
39 #include <QGroupBox>
40 #include <QInputDialog>
41 
42 QgsDualView::QgsDualView( QWidget *parent )
43  : QStackedWidget( parent )
44 {
45  setupUi( this );
46  connect( mFeatureList, &QgsFeatureListView::aboutToChangeEditSelection, this, &QgsDualView::mFeatureList_aboutToChangeEditSelection );
47  connect( mFeatureList, &QgsFeatureListView::currentEditSelectionChanged, this, &QgsDualView::mFeatureList_currentEditSelectionChanged );
48 
49  mConditionalFormatWidget->hide();
50 
51  mPreviewColumnsMenu = new QMenu( this );
52  mActionPreviewColumnsMenu->setMenu( mPreviewColumnsMenu );
53 
54  // Set preview icon
55  mActionExpressionPreview->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) ) );
56 
57  // Connect layer list preview signals
58  connect( mActionExpressionPreview, &QAction::triggered, this, &QgsDualView::previewExpressionBuilder );
59  connect( mFeatureList, &QgsFeatureListView::displayExpressionChanged, this, &QgsDualView::previewExpressionChanged );
60 }
61 
62 void QgsDualView::init( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, const QgsAttributeEditorContext &context, bool loadFeatures )
63 {
64  if ( !layer )
65  return;
66 
67  mLayer = layer;
68 
69  mEditorContext = context;
70 
71  connect( mTableView, &QgsAttributeTableView::willShowContextMenu, this, &QgsDualView::viewWillShowContextMenu );
72  mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
73  connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &QgsDualView::showViewHeaderMenu );
74  connect( mTableView, &QgsAttributeTableView::columnResized, this, &QgsDualView::tableColumnResized );
75  connect( mFeatureList, &QgsFeatureListView::willShowContextMenu, this, &QgsDualView::widgetWillShowContextMenu );
76 
77  initLayerCache( !( request.flags() & QgsFeatureRequest::NoGeometry ) || !request.filterRect().isNull() );
78  initModels( mapCanvas, request, loadFeatures );
79 
80  mConditionalFormatWidget->setLayer( mLayer );
81 
82  mTableView->setModel( mFilterModel );
83  mFeatureList->setModel( mFeatureListModel );
84  delete mAttributeForm;
85  mAttributeForm = new QgsAttributeForm( mLayer, mTempAttributeFormFeature, mEditorContext );
86  mTempAttributeFormFeature = QgsFeature();
87  if ( !context.parentContext() )
88  {
89  mAttributeEditorScrollArea = new QgsScrollArea();
90  mAttributeEditorScrollArea->setWidgetResizable( true );
91  mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea );
92  mAttributeEditorScrollArea->setWidget( mAttributeForm );
93  }
94  else
95  {
96  mAttributeEditor->layout()->addWidget( mAttributeForm );
97  }
98 
99  connect( mAttributeForm, &QgsAttributeForm::widgetValueChanged, this, &QgsDualView::featureFormAttributeChanged );
100  connect( mAttributeForm, &QgsAttributeForm::modeChanged, this, &QgsDualView::formModeChanged );
101  connect( mMasterModel, &QgsAttributeTableModel::modelChanged, mAttributeForm, &QgsAttributeForm::refreshFeature );
103  connect( mFilterModel, &QgsAttributeTableFilterModel::sortColumnChanged, this, &QgsDualView::onSortColumnChanged );
104 
105  if ( mFeatureListPreviewButton->defaultAction() )
106  mFeatureList->setDisplayExpression( mDisplayExpression );
107  else
108  columnBoxInit();
109 
110  // This slows down load of the attribute table heaps and uses loads of memory.
111  //mTableView->resizeColumnsToContents();
112 }
113 
114 void QgsDualView::columnBoxInit()
115 {
116  // load fields
117  QList<QgsField> fields = mLayer->fields().toList();
118 
119  QString defaultField;
120 
121  // default expression: saved value
122  QString displayExpression = mLayer->displayExpression();
123 
124  if ( displayExpression.isEmpty() )
125  {
126  // ... there isn't really much to display
127  displayExpression = QStringLiteral( "'[Please define preview text]'" );
128  }
129 
130  mFeatureListPreviewButton->addAction( mActionExpressionPreview );
131  mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
132 
133  Q_FOREACH ( const QgsField &field, fields )
134  {
135  int fieldIndex = mLayer->fields().lookupField( field.name() );
136  if ( fieldIndex == -1 )
137  continue;
138 
139  QString fieldName = field.name();
140  if ( QgsGui::editorWidgetRegistry()->findBest( mLayer, fieldName ).type() != QLatin1String( "Hidden" ) )
141  {
142  QIcon icon = mLayer->fields().iconForField( fieldIndex );
143  QString text = mLayer->attributeDisplayName( fieldIndex );
144 
145  // Generate action for the preview popup button of the feature list
146  QAction *previewAction = new QAction( icon, text, mFeatureListPreviewButton );
147  connect( previewAction, &QAction::triggered, this, [ = ] { previewColumnChanged( previewAction, fieldName ); } );
148  mPreviewColumnsMenu->addAction( previewAction );
149 
150  if ( text == defaultField )
151  {
152  mFeatureListPreviewButton->setDefaultAction( previewAction );
153  }
154  }
155  }
156 
157  QAction *sortByPreviewExpression = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "sort.svg" ) ), tr( "Sort by preview expression" ), this );
158  connect( sortByPreviewExpression, &QAction::triggered, this, &QgsDualView::sortByPreviewExpression );
159  mFeatureListPreviewButton->addAction( sortByPreviewExpression );
160 
161  QAction *separator = new QAction( mFeatureListPreviewButton );
162  separator->setSeparator( true );
163  mFeatureListPreviewButton->addAction( separator );
164  restoreRecentDisplayExpressions();
165 
166  // If there is no single field found as preview
167  if ( !mFeatureListPreviewButton->defaultAction() )
168  {
169  mFeatureList->setDisplayExpression( displayExpression );
170  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
171  setDisplayExpression( mFeatureList->displayExpression() );
172  }
173  else
174  {
175  mFeatureListPreviewButton->defaultAction()->trigger();
176  }
177 }
178 
180 {
181  setCurrentIndex( view );
182 }
183 
185 {
186  return static_cast< QgsDualView::ViewMode >( currentIndex() );
187 }
188 
190 {
191  // cleanup any existing connections
192  switch ( mFilterModel->filterMode() )
193  {
195  disconnect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
196  break;
197 
201  break;
202 
204  disconnect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
205  break;
206  }
207 
208  QgsFeatureRequest r = mMasterModel->request();
209  bool needsGeometry = filterMode == QgsAttributeTableFilterModel::ShowVisible;
210 
211  bool requiresTableReload = ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) // previous request was subset
212  || ( needsGeometry && r.flags() & QgsFeatureRequest::NoGeometry ) // no geometry for last request
213  || ( mMasterModel->rowCount() == 0 ); // no features
214 
215  if ( !needsGeometry )
217  else
221  r.disableFilter();
222 
223  // setup new connections and filter request parameters
224  switch ( filterMode )
225  {
227  connect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged );
228  if ( mFilterModel->mapCanvas() )
229  {
230  QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
231  r.setFilterRect( rect );
232  }
233  break;
234 
238  break;
239 
241  connect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
242  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
243  break;
244  }
245 
246  if ( requiresTableReload )
247  {
248  mMasterModel->setRequest( r );
249  whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry );
250  mMasterModel->loadLayer();
251  }
252 
253  //update filter model
254  mFilterModel->setFilterMode( filterMode );
255  emit filterChanged();
256 }
257 
258 void QgsDualView::setSelectedOnTop( bool selectedOnTop )
259 {
260  mFilterModel->setSelectedOnTop( selectedOnTop );
261 }
262 
263 void QgsDualView::initLayerCache( bool cacheGeometry )
264 {
265  // Initialize the cache
266  QgsSettings settings;
267  int cacheSize = settings.value( QStringLiteral( "qgis/attributeTableRowCache" ), "10000" ).toInt();
268  mLayerCache = new QgsVectorLayerCache( mLayer, cacheSize, this );
269  mLayerCache->setCacheGeometry( cacheGeometry );
270  if ( 0 == cacheSize || 0 == ( QgsVectorDataProvider::SelectAtId & mLayer->dataProvider()->capabilities() ) )
271  {
272  connect( mLayerCache, &QgsVectorLayerCache::invalidated, this, &QgsDualView::rebuildFullLayerCache );
273  rebuildFullLayerCache();
274  }
275 }
276 
277 void QgsDualView::initModels( QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, bool loadFeatures )
278 {
279  delete mFeatureListModel;
280  delete mFilterModel;
281  delete mMasterModel;
282 
283  mMasterModel = new QgsAttributeTableModel( mLayerCache, this );
284  mMasterModel->setRequest( request );
285  mMasterModel->setEditorContext( mEditorContext );
286  mMasterModel->setExtraColumns( 1 ); // Add one extra column which we can "abuse" as an action column
287 
288  connect( mMasterModel, &QgsAttributeTableModel::progress, this, &QgsDualView::progress );
289  connect( mMasterModel, &QgsAttributeTableModel::finished, this, &QgsDualView::finished );
290 
292 
293  if ( loadFeatures )
294  mMasterModel->loadLayer();
295 
296  mFilterModel = new QgsAttributeTableFilterModel( mapCanvas, mMasterModel, mMasterModel );
297 
298  // The following connections to invalidate() are necessary to keep the filter model in sync
299  // see regression https://issues.qgis.org/issues/15974
300  connect( mMasterModel, &QgsAttributeTableModel::rowsRemoved, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
301  connect( mMasterModel, &QgsAttributeTableModel::rowsInserted, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
302 
304 
305  mFeatureListModel = new QgsFeatureListModel( mFilterModel, mFilterModel );
306  mFeatureListModel->setSortByDisplayExpression( true );
307 }
308 
309 void QgsDualView::restoreRecentDisplayExpressions()
310 {
311  const QVariantList previewExpressions = mLayer->customProperty( QStringLiteral( "dualview/previewExpressions" ) ).toList();
312 
313  for ( const QVariant &previewExpression : previewExpressions )
314  insertRecentlyUsedDisplayExpression( previewExpression.toString() );
315 }
316 
317 void QgsDualView::saveRecentDisplayExpressions() const
318 {
319  if ( ! mLayer )
320  {
321  return;
322  }
323  QList<QAction *> actions = mFeatureListPreviewButton->actions();
324 
325  // Remove existing same action
326  int index = actions.indexOf( mLastDisplayExpressionAction );
327  if ( index != -1 )
328  {
329  QVariantList previewExpressions;
330  for ( ; index < actions.length(); ++index )
331  {
332  QAction *action = actions.at( index );
333  previewExpressions << action->property( "previewExpression" );
334  }
335 
336  mLayer->setCustomProperty( QStringLiteral( "dualview/previewExpressions" ), previewExpressions );
337  }
338 }
339 
340 void QgsDualView::setDisplayExpression( const QString &expression )
341 {
342  mDisplayExpression = expression;
343  insertRecentlyUsedDisplayExpression( expression );
344 }
345 
346 void QgsDualView::insertRecentlyUsedDisplayExpression( const QString &expression )
347 {
348  QList<QAction *> actions = mFeatureListPreviewButton->actions();
349 
350  // Remove existing same action
351  int index = actions.indexOf( mLastDisplayExpressionAction );
352  if ( index != -1 )
353  {
354  for ( int i = 0; index + i < actions.length(); ++i )
355  {
356  QAction *action = actions.at( index );
357  if ( action->text() == expression || i >= 9 )
358  {
359  if ( action == mLastDisplayExpressionAction )
360  mLastDisplayExpressionAction = nullptr;
361  mFeatureListPreviewButton->removeAction( action );
362  }
363  else
364  {
365  if ( !mLastDisplayExpressionAction )
366  mLastDisplayExpressionAction = action;
367  }
368  }
369  }
370 
371  QString name = expression;
372  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) );
373  if ( expression.startsWith( QLatin1String( "COALESCE( \"" ) ) && expression.endsWith( QLatin1String( ", '<NULL>' )" ) ) )
374  {
375  name = expression.mid( 11, expression.length() - 24 ); // Numbers calculated from the COALESCE / <NULL> parts
376 
377  int fieldIndex = mLayer->fields().indexOf( name );
378  if ( fieldIndex != -1 )
379  {
380  name = mLayer->attributeDisplayName( fieldIndex );
381  icon = mLayer->fields().iconForField( fieldIndex );
382  }
383  else
384  {
385  name = expression;
386  }
387  }
388 
389  QAction *previewAction = new QAction( icon, name, mFeatureListPreviewButton );
390  previewAction->setProperty( "previewExpression", expression );
391  connect( previewAction, &QAction::triggered, this, [expression, this]( bool )
392  {
393  setDisplayExpression( expression );
394  mFeatureListPreviewButton->setText( expression );
395  }
396  );
397 
398  mFeatureListPreviewButton->insertAction( mLastDisplayExpressionAction, previewAction );
399  mLastDisplayExpressionAction = previewAction;
400 }
401 
402 void QgsDualView::mFeatureList_aboutToChangeEditSelection( bool &ok )
403 {
404  if ( mLayer->isEditable() && !mAttributeForm->save() )
405  ok = false;
406 }
407 
408 void QgsDualView::mFeatureList_currentEditSelectionChanged( const QgsFeature &feat )
409 {
410  if ( !mAttributeForm )
411  {
412  mTempAttributeFormFeature = feat;
413  }
414  else if ( !mLayer->isEditable() || mAttributeForm->save() )
415  {
416  mAttributeForm->setFeature( feat );
418  }
419  else
420  {
421  // Couldn't save feature
422  }
423 }
424 
426 {
427  mFeatureList->setCurrentFeatureEdited( false );
428  mFeatureList->setEditSelection( fids );
429 }
430 
432 {
433  return mAttributeForm->save();
434 }
435 
437 {
438  mConditionalFormatWidget->setVisible( !mConditionalFormatWidget->isVisible() );
439  mConditionalFormatWidget->viewRules();
440 }
441 
443 {
444  if ( enabled )
446 
448 }
449 
450 void QgsDualView::toggleSearchMode( bool enabled )
451 {
452  if ( enabled )
453  {
456  }
457  else
458  {
460  }
461 }
462 
463 void QgsDualView::previewExpressionBuilder()
464 {
465  // Show expression builder
467 
468  QgsExpressionBuilderDialog dlg( mLayer, mFeatureList->displayExpression(), this, QStringLiteral( "generic" ), context );
469  dlg.setWindowTitle( tr( "Expression Based Preview" ) );
470  dlg.setExpressionText( mFeatureList->displayExpression() );
471 
472  if ( dlg.exec() == QDialog::Accepted )
473  {
474  mFeatureList->setDisplayExpression( dlg.expressionText() );
475  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
476  mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
477  }
478 
479  setDisplayExpression( mFeatureList->displayExpression() );
480 }
481 
482 void QgsDualView::previewColumnChanged( QAction *previewAction, const QString &expression )
483 {
484  if ( !mFeatureList->setDisplayExpression( QStringLiteral( "COALESCE( \"%1\", '<NULL>' )" ).arg( expression ) ) )
485  {
486  QMessageBox::warning( this,
487  tr( "Column Preview" ),
488  tr( "Could not set column '%1' as preview column.\nParser error:\n%2" )
489  .arg( previewAction->text(), mFeatureList->parserErrorString() )
490  );
491  }
492  else
493  {
494  mFeatureListPreviewButton->setText( previewAction->text() );
495  mFeatureListPreviewButton->setIcon( previewAction->icon() );
496  mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
497  }
498 
499  setDisplayExpression( mFeatureList->displayExpression() );
500 }
501 
503 {
504  return mMasterModel->rowCount();
505 }
506 
508 {
509  return mFilterModel->rowCount();
510 }
511 
513 {
514  QAction *action = qobject_cast<QAction *>( sender() );
515 
516  if ( action && action->data().isValid() && action->data().canConvert<QModelIndex>() )
517  {
518  QModelIndex index = action->data().toModelIndex();
519  QVariant var = masterModel()->data( index, Qt::DisplayRole );
520  QApplication::clipboard()->setText( var.toString() );
521  }
522 }
523 
525 {
526  if ( mProgressDlg )
527  mProgressDlg->cancel();
528 }
529 
530 void QgsDualView::hideEvent( QHideEvent *event )
531 {
532  Q_UNUSED( event )
533  saveRecentDisplayExpressions();
534 }
535 
536 void QgsDualView::viewWillShowContextMenu( QMenu *menu, const QModelIndex &atIndex )
537 {
538  if ( !menu )
539  {
540  return;
541  }
542 
543  QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
544 
545  QAction *copyContentAction = new QAction( tr( "Copy Cell Content" ), this );
546  copyContentAction->setData( QVariant::fromValue<QModelIndex>( sourceIndex ) );
547  menu->addAction( copyContentAction );
548  connect( copyContentAction, &QAction::triggered, this, &QgsDualView::copyCellContent );
549 
550  QgsVectorLayer *vl = mFilterModel->layer();
551  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
552  if ( canvas && vl && vl->geometryType() != QgsWkbTypes::NullGeometry )
553  {
554  menu->addAction( tr( "Zoom to Feature" ), this, SLOT( zoomToCurrentFeature() ) );
555  menu->addAction( tr( "Pan to Feature" ), this, SLOT( panToCurrentFeature() ) );
556  menu->addAction( tr( "Flash Feature" ), this, SLOT( flashCurrentFeature() ) );
557  }
558 
559  //add user-defined actions to context menu
560  QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( "Field" ) );
561  if ( !actions.isEmpty() )
562  {
563  QAction *a = menu->addAction( tr( "Run Layer Action" ) );
564  a->setEnabled( false );
565 
566  Q_FOREACH ( const QgsAction &action, actions )
567  {
568  if ( !action.runable() )
569  continue;
570 
571  if ( vl && !vl->isEditable() && action.isEnabledOnlyWhenEditable() )
572  continue;
573 
574  QgsAttributeTableAction *a = new QgsAttributeTableAction( action.name(), this, action.id(), sourceIndex );
575 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
576  menu->addAction( action.name(), a, SLOT( execute() ) );
577 #else
578  menu->addAction( action.name(), a, &QgsAttributeTableAction::execute );
579 #endif
580  }
581  }
582 
583  //add actions from QgsMapLayerActionRegistry to context menu
584  QList<QgsMapLayerAction *> registeredActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer );
585  if ( !registeredActions.isEmpty() )
586  {
587  //add a separator between user defined and standard actions
588  menu->addSeparator();
589 
590  Q_FOREACH ( QgsMapLayerAction *action, registeredActions )
591  {
592  QgsAttributeTableMapLayerAction *a = new QgsAttributeTableMapLayerAction( action->text(), this, action, sourceIndex );
593 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
594  menu->addAction( action->text(), a, SLOT( execut() ) );
595 #else
596  menu->addAction( action->text(), a, &QgsAttributeTableMapLayerAction::execute );
597 #endif
598  }
599  }
600 
601  menu->addSeparator();
602  QgsAttributeTableAction *a = new QgsAttributeTableAction( tr( "Open Form" ), this, QString(), sourceIndex );
603 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
604  menu->addAction( tr( "Open Form" ), a, SLOT( featureForm() ) );
605 #else
606  menu->addAction( tr( "Open Form" ), a, &QgsAttributeTableAction::featureForm );
607 #endif
608 }
609 
610 
611 void QgsDualView::widgetWillShowContextMenu( QgsActionMenu *menu, const QModelIndex &atIndex )
612 {
613  emit showContextMenuExternally( menu, mFilterModel->rowToId( atIndex ) );
614 }
615 
616 
617 void QgsDualView::showViewHeaderMenu( QPoint point )
618 {
619  int col = mTableView->columnAt( point.x() );
620 
621  delete mHorizontalHeaderMenu;
622  mHorizontalHeaderMenu = new QMenu( this );
623 
624  QAction *hide = new QAction( tr( "&Hide Column" ), mHorizontalHeaderMenu );
625  connect( hide, &QAction::triggered, this, &QgsDualView::hideColumn );
626  hide->setData( col );
627  mHorizontalHeaderMenu->addAction( hide );
628  QAction *setWidth = new QAction( tr( "&Set Width…" ), mHorizontalHeaderMenu );
629  connect( setWidth, &QAction::triggered, this, &QgsDualView::resizeColumn );
630  setWidth->setData( col );
631  mHorizontalHeaderMenu->addAction( setWidth );
632  QAction *optimizeWidth = new QAction( tr( "&Autosize" ), mHorizontalHeaderMenu );
633  connect( optimizeWidth, &QAction::triggered, this, &QgsDualView::autosizeColumn );
634  optimizeWidth->setData( col );
635  mHorizontalHeaderMenu->addAction( optimizeWidth );
636 
637  mHorizontalHeaderMenu->addSeparator();
638  QAction *organize = new QAction( tr( "&Organize Columns…" ), mHorizontalHeaderMenu );
639  connect( organize, &QAction::triggered, this, &QgsDualView::organizeColumns );
640  mHorizontalHeaderMenu->addAction( organize );
641  QAction *sort = new QAction( tr( "&Sort…" ), mHorizontalHeaderMenu );
642  connect( sort, &QAction::triggered, this, &QgsDualView::modifySort );
643  mHorizontalHeaderMenu->addAction( sort );
644 
645  mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
646 }
647 
648 void QgsDualView::organizeColumns()
649 {
650  if ( !mLayer )
651  {
652  return;
653  }
654 
655  QgsOrganizeTableColumnsDialog dialog( mLayer, attributeTableConfig(), this );
656  if ( dialog.exec() == QDialog::Accepted )
657  {
658  QgsAttributeTableConfig config = dialog.config();
659  setAttributeTableConfig( config );
660  }
661 }
662 
663 void QgsDualView::tableColumnResized( int column, int width )
664 {
665  QgsAttributeTableConfig config = mConfig;
666  int sourceCol = config.mapVisibleColumnToIndex( column );
667  if ( sourceCol >= 0 && config.columnWidth( sourceCol ) != width )
668  {
669  config.setColumnWidth( sourceCol, width );
670  setAttributeTableConfig( config );
671  }
672 }
673 
674 void QgsDualView::hideColumn()
675 {
676  QAction *action = qobject_cast<QAction *>( sender() );
677  int col = action->data().toInt();
678  QgsAttributeTableConfig config = mConfig;
679  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
680  if ( sourceCol >= 0 )
681  {
682  config.setColumnHidden( sourceCol, true );
683  setAttributeTableConfig( config );
684  }
685 }
686 
687 void QgsDualView::resizeColumn()
688 {
689  QAction *action = qobject_cast<QAction *>( sender() );
690  int col = action->data().toInt();
691  if ( col < 0 )
692  return;
693 
694  QgsAttributeTableConfig config = mConfig;
695  int sourceCol = config.mapVisibleColumnToIndex( col );
696  if ( sourceCol >= 0 )
697  {
698  bool ok = false;
699  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
700  mTableView->columnWidth( col ),
701  0, 1000, 10, &ok );
702  if ( ok )
703  {
704  config.setColumnWidth( sourceCol, width );
705  setAttributeTableConfig( config );
706  }
707  }
708 }
709 
710 void QgsDualView::autosizeColumn()
711 {
712  QAction *action = qobject_cast<QAction *>( sender() );
713  int col = action->data().toInt();
714  mTableView->resizeColumnToContents( col );
715 }
716 
717 void QgsDualView::modifySort()
718 {
719  if ( !mLayer )
720  return;
721 
722  QgsAttributeTableConfig config = mConfig;
723 
724  QDialog orderByDlg;
725  orderByDlg.setWindowTitle( tr( "Configure Attribute Table Sort Order" ) );
726  QDialogButtonBox *dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
727  QGridLayout *layout = new QGridLayout();
728  connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
729  connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
730  orderByDlg.setLayout( layout );
731 
732  QGroupBox *sortingGroupBox = new QGroupBox();
733  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
734  sortingGroupBox->setCheckable( true );
735  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
736  layout->addWidget( sortingGroupBox );
737  sortingGroupBox->setLayout( new QGridLayout() );
738 
739  QgsExpressionBuilderWidget *expressionBuilder = new QgsExpressionBuilderWidget();
741  expressionBuilder->setExpressionContext( context );
742  expressionBuilder->setLayer( mLayer );
743  expressionBuilder->loadFieldNames();
744  expressionBuilder->loadRecent( QStringLiteral( "generic" ) );
745  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? mLayer->displayExpression() : sortExpression() );
746 
747  sortingGroupBox->layout()->addWidget( expressionBuilder );
748 
749  QCheckBox *cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
750  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
751  sortingGroupBox->layout()->addWidget( cbxSortAscending );
752 
753  layout->addWidget( dialogButtonBox );
754  if ( orderByDlg.exec() )
755  {
756  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
757  if ( sortingGroupBox->isChecked() )
758  {
759  setSortExpression( expressionBuilder->expressionText(), sortOrder );
760  config.setSortExpression( expressionBuilder->expressionText() );
761  config.setSortOrder( sortOrder );
762  }
763  else
764  {
765  setSortExpression( QString(), sortOrder );
766  config.setSortExpression( QString() );
767  }
768 
769  setAttributeTableConfig( config );
770  }
771 }
772 
773 void QgsDualView::zoomToCurrentFeature()
774 {
775  QModelIndex currentIndex = mTableView->currentIndex();
776  if ( !currentIndex.isValid() )
777  {
778  return;
779  }
780 
781  QgsFeatureIds ids;
782  ids.insert( mFilterModel->rowToId( currentIndex ) );
783  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
784  if ( canvas )
785  {
786  canvas->zoomToFeatureIds( mLayer, ids );
787  }
788 }
789 
790 void QgsDualView::panToCurrentFeature()
791 {
792  QModelIndex currentIndex = mTableView->currentIndex();
793  if ( !currentIndex.isValid() )
794  {
795  return;
796  }
797 
798  QgsFeatureIds ids;
799  ids.insert( mFilterModel->rowToId( currentIndex ) );
800  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
801  if ( canvas )
802  {
803  canvas->panToFeatureIds( mLayer, ids );
804  }
805 }
806 
807 void QgsDualView::flashCurrentFeature()
808 {
809  QModelIndex currentIndex = mTableView->currentIndex();
810  if ( !currentIndex.isValid() )
811  {
812  return;
813  }
814 
815  QgsFeatureIds ids;
816  ids.insert( mFilterModel->rowToId( currentIndex ) );
817  QgsMapCanvas *canvas = mFilterModel->mapCanvas();
818  if ( canvas )
819  {
820  canvas->flashFeatureIds( mLayer, ids );
821  }
822 }
823 
824 void QgsDualView::rebuildFullLayerCache()
825 {
826  connect( mLayerCache, &QgsVectorLayerCache::progress, this, &QgsDualView::progress, Qt::UniqueConnection );
827  connect( mLayerCache, &QgsVectorLayerCache::finished, this, &QgsDualView::finished, Qt::UniqueConnection );
828 
829  mLayerCache->setFullCache( true );
830 }
831 
832 void QgsDualView::previewExpressionChanged( const QString &expression )
833 {
834  mLayer->setDisplayExpression( expression );
835 }
836 
837 void QgsDualView::onSortColumnChanged()
838 {
840  if ( cfg.sortExpression() != mFilterModel->sortExpression() ||
841  cfg.sortOrder() != mFilterModel->sortOrder() )
842  {
843  cfg.setSortExpression( mFilterModel->sortExpression() );
844  cfg.setSortOrder( mFilterModel->sortOrder() );
846  }
847 }
848 
849 void QgsDualView::sortByPreviewExpression()
850 {
851  Qt::SortOrder sortOrder = Qt::AscendingOrder;
852  if ( mFeatureList->displayExpression() == sortExpression() )
853  {
854  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
855  }
856  setSortExpression( mFeatureList->displayExpression(), sortOrder );
857 }
858 
859 void QgsDualView::updateSelectedFeatures()
860 {
861  QgsFeatureRequest r = mMasterModel->request();
863  return; // already requested all features
864 
865  r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
866  mMasterModel->setRequest( r );
867  mMasterModel->loadLayer();
868  emit filterChanged();
869 }
870 
871 void QgsDualView::extentChanged()
872 {
873  QgsFeatureRequest r = mMasterModel->request();
874  if ( mFilterModel->mapCanvas() && ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) )
875  {
876  QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
877  r.setFilterRect( rect );
878  mMasterModel->setRequest( r );
879  mMasterModel->loadLayer();
880  }
881  emit filterChanged();
882 }
883 
884 void QgsDualView::featureFormAttributeChanged( const QString &attribute, const QVariant &value, bool attributeChanged )
885 {
886  Q_UNUSED( attribute );
887  Q_UNUSED( value );
888  if ( attributeChanged )
889  mFeatureList->setCurrentFeatureEdited( true );
890 }
891 
893 {
894  mFilterModel->setFilteredFeatures( filteredFeatures );
895 }
896 
898 {
899  mMasterModel->setRequest( request );
900 }
901 
903 {
904  mTableView->setFeatureSelectionManager( featureSelectionManager );
905  mFeatureList->setFeatureSelectionManager( featureSelectionManager );
906 
907  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
908  delete mFeatureSelectionManager;
909 
910  mFeatureSelectionManager = featureSelectionManager;
911 }
912 
914 {
915  mConfig = config;
916  mConfig.update( mLayer->fields() );
917  mLayer->setAttributeTableConfig( mConfig );
918  mFilterModel->setAttributeTableConfig( mConfig );
919  mTableView->setAttributeTableConfig( mConfig );
920 }
921 
922 void QgsDualView::setSortExpression( const QString &sortExpression, Qt::SortOrder sortOrder )
923 {
924  if ( sortExpression.isNull() )
925  mFilterModel->sort( -1 );
926  else
927  mFilterModel->sort( sortExpression, sortOrder );
928 
929  mConfig.setSortExpression( sortExpression );
930  mConfig.setSortOrder( sortOrder );
931  setAttributeTableConfig( mConfig );
932 }
933 
935 {
936  return mFilterModel->sortExpression();
937 }
938 
940 {
941  return mConfig;
942 }
943 
944 void QgsDualView::progress( int i, bool &cancel )
945 {
946  if ( !mProgressDlg )
947  {
948  mProgressDlg = new QProgressDialog( tr( "Loading features…" ), tr( "Abort" ), 0, 0, this );
949  mProgressDlg->setWindowTitle( tr( "Attribute Table" ) );
950  mProgressDlg->setWindowModality( Qt::WindowModal );
951  mProgressDlg->show();
952  }
953 
954  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
955  QCoreApplication::processEvents();
956 
957  cancel = mProgressDlg && mProgressDlg->wasCanceled();
958 }
959 
960 void QgsDualView::finished()
961 {
962  delete mProgressDlg;
963  mProgressDlg = nullptr;
964 }
965 
966 /*
967  * QgsAttributeTableAction
968  */
969 
971 {
972  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
973 }
974 
976 {
977  QgsFeatureIds editedIds;
978  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
979  mDualView->setCurrentEditSelection( editedIds );
980  mDualView->setView( QgsDualView::AttributeEditor );
981 }
982 
983 /*
984  * QgsAttributeTableMapLayerAction
985  */
986 
988 {
989  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
990 }
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.
void setFilterMode(QgsAttributeTableFilterModel::FilterMode filterMode)
Set the filter mode.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
void setSortExpression(const QString &sortExpression)
Set the sort expression used for sorting.
const Flags & flags() const
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:62
void setExpressionText(const QString &text)
void willShowContextMenu(QMenu *menu, const QModelIndex &atIndex)
Is emitted, in order to provide a hook to add additional* menu entries to the context menu...
QgsMapCanvas * mapCanvas() const
Returns the map canvas.
QgsAttributeTableConfig config() const
Gets the updated configuration.
QString name
Definition: qgsfield.h:57
void setSelectedOnTop(bool selectedOnTop)
Changes the sort order of the features.
void filterExpressionSet(const QString &expression, QgsAttributeForm::FilterType type)
Is emitted when a filter expression is set using the view.
void setSortOrder(Qt::SortOrder sortOrder)
Set the sort order.
void setFilterMode(FilterMode filterMode)
Set the filter mode the filter will use.
void toggleSearchMode(bool enabled)
Toggles whether search mode should be enabled in the form.
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
Set the feature selection model.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
void invalidated()
The cache has been invalidated and cleared.
void openConditionalStyles()
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
This class contains context information for attribute editor widgets.
int mapVisibleColumnToIndex(int visibleColumn) const
Maps a visible column index to its original column index.
void setLayer(QgsVectorLayer *layer)
Sets layer in order to get the fields and values.
bool save()
Save all the values from the editors to the layer.
ViewMode
The view modes, in which this widget can present information.
Definition: qgsdualview.h:53
void willShowContextMenu(QgsActionMenu *menu, const QModelIndex &atIndex)
Is emitted, when the context menu is created to add the specific actions to it.
void loadRecent(const QString &collection="generic")
Loads the recent expressions from the given collection.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:435
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
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.
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer&#39;s CRS
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.
const QgsFeatureRequest & request() const
Gets the the feature request.
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.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
void hideEvent(QHideEvent *event) override
void setView(ViewMode view)
Change the current view mode.
virtual void setFilteredFeatures(const QgsFeatureIds &ids)
Specify a list of features, which the filter will accept.
QVariant data(const QModelIndex &index, int role) const override
Returns data on the given index.
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table config which should be used to control the appearance of the attribute table...
QString sortExpression() const
Gets the expression used for sorting.
QgsDualView(QWidget *parent=nullptr)
Constructor.
Definition: qgsdualview.cpp:42
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
Definition: qgsdualview.h:66
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
void setColumnWidth(int column, int width)
Sets the width of a column.
void setSortExpression(const QString &sortExpression, Qt::SortOrder sortOrder=Qt::AscendingOrder)
Set the expression used for sorting the table and feature list.
QString name() const
The name of the action. This may be a longer description.
Definition: qgsaction.h:124
Qt::SortOrder sortOrder() const
Gets the sort order.
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer.
FilterMode filterMode()
The current filterModel.
void setExtraColumns(int extraColumns)
Empty extra columns to announce from this model.
void setFeature(const QgsFeature &feature)
Update all editors to correspond to a different feature.
FilterMode
The filter mode defines how the rows should be filtered.
void flashFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids, const QColor &startColor=QColor(255, 0, 0, 255), const QColor &endColor=QColor(255, 0, 0, 0), int flashes=3, int duration=500)
Causes a set of features with matching ids from a vector layer to flash within the canvas...
Dialog for organising (hiding and reordering) columns in the attributes table.
void aboutToChangeEditSelection(bool &ok)
This class is a menu that is populated automatically with the actions defined for a given layer...
Definition: qgsactionmenu.h:38
void setEditorContext(const QgsAttributeEditorContext &context)
Sets the context in which this table is shown.
QgsFeatureRequest & disableFilter()
Disables filter conditions.
void filterExpressionSet(const QString &expression, QgsAttributeForm::FilterType type)
Is emitted when a filter expression is set using the form.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories...
Definition: qgsgui.cpp:58
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 ...
ViewMode view() const
Returns the current view mode.
void panToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Centers canvas extent to feature ids.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
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:154
void refreshFeature()
reload current feature
void displayExpressionChanged(const QString &expression)
Is emitted, whenever the display expression is successfully changed.
void filterChanged()
Is emitted, whenever the filter changes.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
This signal is emitted when selection was changed.
FilterType filterType() const
Returns the filter type which is currently set on this request.
void loadFieldNames()
Loads all the field names from the layer.
Show only features which have unsaved changes.
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.
QgsAttributeTableConfig attributeTableConfig() const
The config used for the attribute table.
QUuid id() const
Returns a unique id for this action.
Definition: qgsaction.h:134
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context for the widget.
This class caches features of a given QgsVectorLayer.
QgsAttributeTableModel * masterModel() const
Returns the model which has the information about all features (not only filtered) ...
Definition: qgsdualview.h:161
bool saveEditChanges()
saveEditChanges
Show only features whose ids are on the filter list. {.
void progress(int i, bool &cancel)
void setRequest(const QgsFeatureRequest &request)
Set the request.
QgsAttributeTableFilterModel::FilterMode filterMode()
Gets the filter mode.
Definition: qgsdualview.h:118
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:225
void zoomToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Set canvas extent to the bounding box of a set of features.
No filter is applied.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
void setFullCache(bool fullCache)
This enables or disables full caching.
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Sort by the given column using the given order.
QString sortExpression() const
The expression which is used to sort the attribute table.
void setColumnHidden(int column, bool hidden)
Sets whether the specified column should be hidden.
Single edit mode, for editing a single feature.
void displayExpressionChanged(const QString &expression)
Is emitted, whenever the display expression is successfully changed.
QString expressionText()
Gets the expression string that has been set in the expression area.
QString sortExpression() const
Gets the expression used for sorting the table and feature list.
void setExpressionText(const QString &expression)
Sets the expression string for the widget.
const QgsAttributeEditorContext * parentContext() const
bool runable() const
Checks if the action is runable on the current platform.
Definition: qgsaction.cpp:29
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
void setSortByDisplayExpression(bool sortByDisplayExpression)
Sort this model by its display expression.
void setFilteredFeatures(const QgsFeatureIds &filteredFeatures)
Set a list of currently visible features.
This is a container for configuration of the attribute table.
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 copyCellContent() const
Copy the content of the selected cell in the clipboard.
void currentEditSelectionChanged(QgsFeature &feat)
Is emitted, whenever the current edit selection has been changed.
Represents a vector layer which manages a vector based data sets.
void sortColumnChanged(int column, Qt::SortOrder order)
Is emitted whenever the sort column is changed.
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Definition: qgsgui.cpp:78
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.
bool isEnabledOnlyWhenEditable() const
Returns whether only enabled in editable mode.
Definition: qgsaction.h:173
An action which can run on map layers.
int columnWidth(int column) const
Returns the width of a column, or -1 if column should use default width.
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.
void rulesUpdated(const QString &fieldName)
Emitted when the conditional styling rules are updated.
void modeChanged(QgsAttributeEditorContext::Mode mode)
Emitted when the form changes mode.