QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
qgsattributetablefiltermodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  QgsAttributeTableFilterModel.cpp
3  --------------------------------------
4  Date : Feb 2009
5  Copyright : (C) 2009 Vita Cizek
6  Email : weetya (at) gmail.com
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 <QItemSelectionModel>
17 #include <QApplication>
18 
19 #include "qgis.h"
21 #include "qgsattributetablemodel.h"
22 #include "qgsfeatureiterator.h"
23 #include "qgsvectorlayer.h"
25 #include "qgsfeature.h"
26 #include "qgsmapcanvas.h"
27 #include "qgslogger.h"
28 #include "qgsrenderer.h"
31 #include "qgsvectorlayercache.h"
32 #include "qgsrendercontext.h"
33 #include "qgsmapcanvasutils.h"
34 
36 // Filter Model //
38 
40  : QSortFilterProxyModel( parent )
41  , mCanvas( canvas )
42 {
43  setSourceModel( sourceModel );
44  setDynamicSortFilter( true );
45  setSortRole( static_cast< int >( QgsAttributeTableModel::CustomRole::Sort ) );
46  connect( layer(), &QgsVectorLayer::selectionChanged, this, &QgsAttributeTableFilterModel::selectionChanged );
47 
48  mReloadVisibleTimer.setSingleShot( true );
49  connect( &mReloadVisibleTimer, &QTimer::timeout, this, &QgsAttributeTableFilterModel::reloadVisible );
50  mFilterFeaturesTimer.setSingleShot( true );
51  connect( &mFilterFeaturesTimer, &QTimer::timeout, this, &QgsAttributeTableFilterModel::filterFeatures );
52 }
53 
54 bool QgsAttributeTableFilterModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
55 {
56  if ( mSelectedOnTop )
57  {
58  const bool leftSelected = layer()->selectedFeatureIds().contains( masterModel()->rowToId( left.row() ) );
59  const bool rightSelected = layer()->selectedFeatureIds().contains( masterModel()->rowToId( right.row() ) );
60 
61  if ( leftSelected && !rightSelected )
62  {
63  return sortOrder() == Qt::AscendingOrder;
64  }
65  else if ( rightSelected && !leftSelected )
66  {
67  return sortOrder() == Qt::DescendingOrder;
68  }
69  }
70 
71  if ( mTableModel->sortCacheExpression().isEmpty() )
72  {
73  //shortcut when no sort order set
74  return false;
75  }
76 
77  return qgsVariantLessThan( left.data( static_cast< int >( QgsAttributeTableModel::CustomRole::Sort ) ),
78  right.data( static_cast< int >( QgsAttributeTableModel::CustomRole::Sort ) ) );
79 }
80 
81 void QgsAttributeTableFilterModel::sort( int column, Qt::SortOrder order )
82 {
83  if ( order != Qt::AscendingOrder && order != Qt::DescendingOrder )
84  order = Qt::AscendingOrder;
85  if ( column < 0 || column >= mColumnMapping.size() )
86  {
87  sort( QString() );
88  }
89  else
90  {
91  const int myColumn = mColumnMapping.at( column );
92  masterModel()->prefetchColumnData( myColumn );
93  QSortFilterProxyModel::sort( myColumn, order );
94  }
95  emit sortColumnChanged( column, order );
96 }
97 
98 QVariant QgsAttributeTableFilterModel::data( const QModelIndex &index, int role ) const
99 {
100  if ( mapColumnToSource( index.column() ) == -1 ) // actions
101  {
102  if ( role == static_cast< int >( CustomRole::Type ) )
103  return ColumnTypeActionButton;
104  else if ( role == static_cast< int >( QgsAttributeTableModel::CustomRole::FeatureId ) )
105  {
106  const QModelIndex fieldIndex = QSortFilterProxyModel::mapToSource( QSortFilterProxyModel::index( index.row(), 0, index.parent() ) );
107  return sourceModel()->data( fieldIndex, static_cast< int >( QgsAttributeTableModel::CustomRole::FeatureId ) );
108  }
109  }
110  else if ( role == static_cast< int >( CustomRole::Type ) )
111  return ColumnTypeField;
112 
113  return QSortFilterProxyModel::data( index, role );
114 }
115 
116 QVariant QgsAttributeTableFilterModel::headerData( int section, Qt::Orientation orientation, int role ) const
117 {
118  if ( orientation == Qt::Horizontal )
119  {
120  if ( mColumnMapping.at( section ) == -1 && role == Qt::DisplayRole )
121  return tr( "Actions" );
122  else
123  return QSortFilterProxyModel::headerData( section, orientation, role );
124  }
125  else
126  {
127  if ( role == Qt::DisplayRole )
128  return section + 1;
129  else
130  {
131  const int sourceSection = mapToSource( index( section, ( !mColumnMapping.isEmpty() && mColumnMapping.at( 0 ) == -1 ) ? 1 : 0 ) ).row();
132  return sourceModel()->headerData( sourceSection, orientation, role );
133  }
134  }
135 }
136 
138 {
139  return mColumnMapping.indexOf( -1 );
140 }
141 
142 int QgsAttributeTableFilterModel::columnCount( const QModelIndex &parent ) const
143 {
144  Q_UNUSED( parent )
145  return mColumnMapping.count();
146 }
147 
149 {
150  const QgsAttributeTableConfig oldConfig = mConfig;
151  mConfig = config;
152  mConfig.update( layer()->fields() );
153 
154  if ( !force && mConfig.hasSameColumns( oldConfig ) )
155  {
156  return;
157  }
158 
159  QVector<int> newColumnMapping;
160  const auto constColumns = mConfig.columns();
161  for ( const QgsAttributeTableConfig::ColumnConfig &columnConfig : constColumns )
162  {
163  // Hidden? Forget about this column
164  if ( columnConfig.hidden )
165  continue;
166 
167  // The new value for the mapping (field index or -1 for action column)
168  const int newValue = ( columnConfig.type == QgsAttributeTableConfig::Action ) ? -1 : layer()->fields().lookupField( columnConfig.name );
169  newColumnMapping << newValue;
170  }
171 
172  if ( newColumnMapping != mColumnMapping )
173  {
174  bool requiresReset = false;
175  int firstRemovedColumn = -1;
176  int removedColumnCount = 0;
177 
178  // Check if there have a contiguous set of columns have been removed or if we require a full reset
179  for ( int i = 0; i < std::min( newColumnMapping.size(), mColumnMapping.size() - removedColumnCount ); ++i )
180  {
181  if ( newColumnMapping.at( i ) == mColumnMapping.at( i + removedColumnCount ) )
182  continue;
183 
184  if ( firstRemovedColumn == -1 )
185  {
186  firstRemovedColumn = i;
187 
188  while ( i < mColumnMapping.size() - removedColumnCount && mColumnMapping.at( i + removedColumnCount ) != newColumnMapping.at( i ) )
189  {
190  ++removedColumnCount;
191  }
192  }
193  else
194  {
195  requiresReset = true;
196  break;
197  }
198  }
199 
200  // No difference found so far
201  if ( firstRemovedColumn == -1 )
202  {
203  if ( newColumnMapping.size() > mColumnMapping.size() )
204  {
205  // More columns: appended to the end
206  beginInsertColumns( QModelIndex(), mColumnMapping.size(), newColumnMapping.size() - 1 );
207  mColumnMapping = newColumnMapping;
208  endInsertColumns();
209  }
210  else
211  {
212  // Less columns: removed from the end
213  beginRemoveColumns( QModelIndex(), newColumnMapping.size(), mColumnMapping.size() - 1 );
214  mColumnMapping = newColumnMapping;
215  endRemoveColumns();
216  }
217  }
218  else
219  {
220  if ( newColumnMapping.size() == mColumnMapping.size() - removedColumnCount )
221  {
222  //the amount of removed column in the model need to be equal removedColumnCount
223  beginRemoveColumns( QModelIndex(), firstRemovedColumn, firstRemovedColumn + removedColumnCount - 1 );
224  mColumnMapping = newColumnMapping;
225  endRemoveColumns();
226  }
227  else
228  {
229  requiresReset = true;
230  }
231  }
232 
233  if ( requiresReset )
234  {
235  beginResetModel();
236  mColumnMapping = newColumnMapping;
237  endResetModel();
238  }
239  }
240 
241  if ( !config.sortExpression().isEmpty() )
242  sort( config.sortExpression(), config.sortOrder() );
243 }
244 
246 {
247  mFilterExpression = expression;
248  mFilterExpressionContext = context;
249 }
250 
251 void QgsAttributeTableFilterModel::sort( const QString &expression, Qt::SortOrder order )
252 {
253  if ( order != Qt::AscendingOrder && order != Qt::DescendingOrder )
254  order = Qt::AscendingOrder;
255 
256  QSortFilterProxyModel::sort( -1 );
257  masterModel()->prefetchSortData( expression );
258  QSortFilterProxyModel::sort( 0, order );
259 }
260 
262 {
263  return masterModel()->sortCacheExpression();
264 }
265 
267 {
268  if ( mSelectedOnTop != selectedOnTop )
269  {
270  mSelectedOnTop = selectedOnTop;
271  int column = sortColumn();
272  Qt::SortOrder order = sortOrder();
273 
274  // set default sort values if they are not correctly set
275  if ( column < 0 )
276  column = 0;
277 
278  if ( order != Qt::AscendingOrder && order != Qt::DescendingOrder )
279  order = Qt::AscendingOrder;
280 
281  sort( 0, Qt::AscendingOrder );
282  invalidate();
283  }
284 }
285 
287 {
288  mTableModel = sourceModel;
289 
290  for ( int i = 0; i < mTableModel->columnCount() - mTableModel->extraColumns(); ++i )
291  {
292  mColumnMapping.append( i );
293  }
294 
295  QSortFilterProxyModel::setSourceModel( sourceModel );
296 
297  // Disconnect any code to update columns in the parent, we handle this manually
298  disconnect( mTableModel, SIGNAL( columnsAboutToBeInserted( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsAboutToBeInserted( QModelIndex, int, int ) ) );
299  disconnect( mTableModel, SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsInserted( QModelIndex, int, int ) ) );
300  disconnect( mTableModel, SIGNAL( columnsAboutToBeRemoved( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsAboutToBeRemoved( QModelIndex, int, int ) ) );
301  disconnect( mTableModel, SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsRemoved( QModelIndex, int, int ) ) );
302  // The following connections are needed in order to keep the filter model in sync, see: regression #15974
303  connect( mTableModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &QgsAttributeTableFilterModel::onColumnsChanged );
304  connect( mTableModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &QgsAttributeTableFilterModel::onColumnsChanged );
305 
306 }
307 
309 {
310  return mSelectedOnTop;
311 }
312 
314 {
315  mFilteredFeatures = ids;
316  if ( mFilterMode != ShowFilteredList &&
317  mFilterMode != ShowInvalid )
318  {
320  }
321  invalidateFilter();
322 }
323 
325 {
326  QgsFeatureIds ids;
327  ids.reserve( rowCount() );
328  for ( int i = 0; i < rowCount(); ++i )
329  {
330  const QModelIndex row = index( i, 0 );
331  ids << rowToId( row );
332  }
333  return ids;
334 }
335 
337 {
338  if ( filterMode != mFilterMode )
339  {
342  mFilterMode = filterMode;
343  invalidate();
344 
345  if ( mFilterMode == QgsAttributeTableFilterModel::ShowInvalid )
346  {
347  filterFeatures();
348  }
349  }
350 }
351 
353 {
354  // cleanup existing connections
355  switch ( mFilterMode )
356  {
357  case ShowVisible:
358  disconnect( mCanvas, &QgsMapCanvas::extentsChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
359  disconnect( mCanvas, &QgsMapCanvas::temporalRangeChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
360  disconnect( layer(), &QgsVectorLayer::featureAdded, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
361  disconnect( layer(), &QgsVectorLayer::geometryChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
362  break;
363  case ShowAll:
364  case ShowEdited:
365  case ShowSelected:
366  break;
367  case ShowFilteredList:
368  case ShowInvalid:
369  disconnect( layer(), &QgsVectorLayer::featureAdded, this, &QgsAttributeTableFilterModel::startTimedFilterFeatures );
370  disconnect( layer(), &QgsVectorLayer::attributeValueChanged, this, &QgsAttributeTableFilterModel::onAttributeValueChanged );
371  disconnect( layer(), &QgsVectorLayer::geometryChanged, this, &QgsAttributeTableFilterModel::onGeometryChanged );
372  break;
373  }
374 }
375 
377 {
378  // setup new connections
379  switch ( filterMode )
380  {
381  case ShowVisible:
382  connect( mCanvas, &QgsMapCanvas::extentsChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
383  connect( mCanvas, &QgsMapCanvas::temporalRangeChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
384  connect( layer(), &QgsVectorLayer::featureAdded, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
385  connect( layer(), &QgsVectorLayer::geometryChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
387  break;
388  case ShowAll:
389  case ShowEdited:
390  case ShowSelected:
391  break;
392  case ShowFilteredList:
393  case ShowInvalid:
394  connect( layer(), &QgsVectorLayer::featureAdded, this, &QgsAttributeTableFilterModel::startTimedFilterFeatures );
395  connect( layer(), &QgsVectorLayer::attributeValueChanged, this, &QgsAttributeTableFilterModel::onAttributeValueChanged );
396  connect( layer(), &QgsVectorLayer::geometryChanged, this, &QgsAttributeTableFilterModel::onGeometryChanged );
397  break;
398  }
399 }
400 
401 bool QgsAttributeTableFilterModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
402 {
403  Q_UNUSED( sourceParent )
404  switch ( mFilterMode )
405  {
406  case ShowAll:
407  return true;
408 
409  case ShowFilteredList:
410  case ShowInvalid:
411  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
412 
413  case ShowSelected:
414  return layer()->selectedFeatureIds().contains( masterModel()->rowToId( sourceRow ) );
415 
416  case ShowVisible:
417  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
418 
419  case ShowEdited:
420  {
421  QgsVectorLayerEditBuffer *editBuffer = layer()->editBuffer();
422  if ( editBuffer )
423  {
424  const QgsFeatureId fid = masterModel()->rowToId( sourceRow );
425 
426  if ( editBuffer->isFeatureAdded( fid ) )
427  return true;
428 
429  if ( editBuffer->isFeatureAttributesChanged( fid ) )
430  return true;
431 
432  if ( editBuffer->isFeatureGeometryChanged( fid ) )
433  return true;
434 
435  return false;
436  }
437  return false;
438  }
439 
440  default:
441  Q_ASSERT( false ); // In debug mode complain
442  return true; // In release mode accept row
443  }
444  // returns are handled in their respective case statement above
445 }
446 
448 {
449  reloadVisible();
450 }
451 
452 void QgsAttributeTableFilterModel::reloadVisible()
453 {
455  invalidateFilter();
456  emit visibleReloaded();
457 }
458 
459 void QgsAttributeTableFilterModel::onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value )
460 {
461  Q_UNUSED( fid );
462  Q_UNUSED( value );
463 
464  if ( mFilterMode == QgsAttributeTableFilterModel::ShowInvalid || mFilterExpression.referencedAttributeIndexes( layer()->fields() ).contains( idx ) )
465  {
466  startTimedFilterFeatures();
467  }
468 }
469 
470 void QgsAttributeTableFilterModel::onGeometryChanged()
471 {
472  if ( mFilterMode == QgsAttributeTableFilterModel::ShowInvalid || mFilterExpression.needsGeometry() )
473  {
474  startTimedFilterFeatures();
475  }
476 }
477 
478 void QgsAttributeTableFilterModel::startTimedReloadVisible()
479 {
480  mReloadVisibleTimer.start( 10 );
481 }
482 
483 void QgsAttributeTableFilterModel::startTimedFilterFeatures()
484 {
485  mFilterFeaturesTimer.start( 10 );
486 }
487 
489 {
490  if ( !mFilterExpression.isValid() )
491  return;
492 
494  QgsDistanceArea distanceArea;
495 
496  distanceArea.setSourceCrs( mTableModel->layer()->crs(), QgsProject::instance()->transformContext() );
497  distanceArea.setEllipsoid( QgsProject::instance()->ellipsoid() );
498 
499  const bool fetchGeom = mFilterExpression.needsGeometry();
500 
501  QApplication::setOverrideCursor( Qt::WaitCursor );
502 
503  mFilterExpression.setGeomCalculator( &distanceArea );
504  mFilterExpression.setDistanceUnits( QgsProject::instance()->distanceUnits() );
505  mFilterExpression.setAreaUnits( QgsProject::instance()->areaUnits() );
506  QgsFeatureRequest request( mTableModel->request() );
507  request.setSubsetOfAttributes( mFilterExpression.referencedColumns(), mTableModel->layer()->fields() );
508  if ( !fetchGeom )
509  {
511  }
512  else
513  {
514  // force geometry extraction if the filter requests it
515  request.setFlags( request.flags() & ~static_cast<int>( Qgis::FeatureRequestFlag::NoGeometry ) );
516  }
517  QgsFeatureIterator featIt = mTableModel->layer()->getFeatures( request );
518 
519  QgsFeature f;
520 
521  // Record the first evaluation error
522  QString error;
523 
524  while ( featIt.nextFeature( f ) )
525  {
526  mFilterExpressionContext.setFeature( f );
527  if ( mFilterExpression.evaluate( &mFilterExpressionContext ).toInt() != 0 )
528  filteredFeatures << f.id();
529 
530  // check if there were errors during evaluating
531  if ( mFilterExpression.hasEvalError() && error.isEmpty() )
532  {
533  error = mFilterExpression.evalErrorString( );
534  }
535  }
536 
537  featIt.close();
538 
540 
541  QApplication::restoreOverrideCursor();
542 
543  emit featuresFiltered();
544 
545  if ( ! error.isEmpty() )
546  {
547  emit filterError( error );
548  }
549 
550 }
551 
552 
553 void QgsAttributeTableFilterModel::selectionChanged()
554 {
555  if ( ShowSelected == mFilterMode )
556  {
557  invalidateFilter();
558  }
559  else if ( mSelectedOnTop )
560  {
561  invalidate();
562  }
563 }
564 
565 void QgsAttributeTableFilterModel::onColumnsChanged()
566 {
567  setAttributeTableConfig( mConfig );
568 }
569 
570 int QgsAttributeTableFilterModel::mapColumnToSource( int column ) const
571 {
572  if ( mColumnMapping.isEmpty() )
573  return column;
574  if ( column < 0 || column >= mColumnMapping.size() )
575  return -1;
576  else
577  return mColumnMapping.at( column );
578 }
579 
580 int QgsAttributeTableFilterModel::mapColumnFromSource( int column ) const
581 {
582  if ( mColumnMapping.isEmpty() )
583  return column;
584  else
585  return mColumnMapping.indexOf( column );
586 }
587 
589 {
590  if ( !layer() )
591  return;
592 
593  bool filter = false;
594  const QgsRectangle rect = mCanvas->mapSettings().mapToLayerCoordinates( layer(), mCanvas->extent() );
595  QgsRenderContext renderContext;
597 
598  mFilteredFeatures.clear();
599  if ( !layer()->renderer() )
600  {
601  QgsDebugError( QStringLiteral( "Cannot get renderer" ) );
602  return;
603  }
604 
605  std::unique_ptr< QgsFeatureRenderer > renderer( layer()->renderer()->clone() );
606 
607  const QgsMapSettings &ms = mCanvas->mapSettings();
608  if ( !layer()->isInScaleRange( ms.scale() ) )
609  {
610  QgsDebugMsgLevel( QStringLiteral( "Out of scale limits" ), 2 );
611  }
612  else
613  {
614  if ( renderer->capabilities() & QgsFeatureRenderer::ScaleDependent )
615  {
616  // setup scale
617  // mapRenderer()->renderContext()->scale is not automatically updated when
618  // render extent changes (because it's scale is used to identify if changed
619  // since last render) -> use local context
620  renderContext.setExtent( ms.visibleExtent() );
621  renderContext.setMapToPixel( ms.mapToPixel() );
622  renderContext.setRendererScale( ms.scale() );
623  }
624 
625  filter = renderer->capabilities() & QgsFeatureRenderer::Filter;
626  }
627 
628  renderer->startRender( renderContext, layer()->fields() );
629 
630  QgsFeatureRequest r( masterModel()->request() );
632  {
633  r.setFilterRect( r.filterRect().intersect( rect ) );
634  }
635  else
636  {
637  r.setFilterRect( rect );
638  }
639 
640  const QString canvasFilter = QgsMapCanvasUtils::filterForLayer( mCanvas, layer() );
641  if ( canvasFilter == QLatin1String( "FALSE" ) )
642  return;
643  if ( !canvasFilter.isEmpty() )
644  r.setFilterExpression( canvasFilter );
645 
647 
648  QgsFeature f;
649 
650  while ( features.nextFeature( f ) )
651  {
652  renderContext.expressionContext().setFeature( f );
653  if ( !filter || renderer->willRenderFeature( f, renderContext ) )
654  {
655  mFilteredFeatures << f.id();
656  }
657 #if 0
658  if ( t.elapsed() > 5000 )
659  {
660  bool cancel = false;
661  emit progress( i, cancel );
662  if ( cancel )
663  break;
664 
665  t.restart();
666  }
667 #endif
668  }
669 
670  features.close();
671 
672  if ( renderer->capabilities() & QgsFeatureRenderer::ScaleDependent )
673  {
674  renderer->stopRender( renderContext );
675  }
676 }
677 
679 {
680  return masterModel()->rowToId( mapToSource( row ).row() );
681 }
682 
684 {
685  return mapFromMaster( masterModel()->idToIndex( fid ) );
686 }
687 
689 {
690  QModelIndexList indexes;
691  const auto constIdToIndexList = masterModel()->idToIndexList( fid );
692  for ( const QModelIndex &idx : constIdToIndexList )
693  {
694  indexes.append( mapFromMaster( idx ) );
695  }
696 
697  return indexes;
698 }
699 
700 QModelIndex QgsAttributeTableFilterModel::mapToSource( const QModelIndex &proxyIndex ) const
701 {
702  if ( !proxyIndex.isValid() )
703  return QModelIndex();
704 
705  int sourceColumn = mapColumnToSource( proxyIndex.column() );
706 
707  // For the action column there is no matching column in the source model, just return the first one
708  // so we are still able to query for the feature id, the feature...
709  if ( sourceColumn == -1 )
710  sourceColumn = 0;
711 
712  return QSortFilterProxyModel::mapToSource( index( proxyIndex.row(), sourceColumn, proxyIndex.parent() ) );
713 }
714 
715 QModelIndex QgsAttributeTableFilterModel::mapFromSource( const QModelIndex &sourceIndex ) const
716 {
717  const QModelIndex proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
718 
719  if ( proxyIndex.column() < 0 )
720  return QModelIndex();
721 
722  int col = mapColumnFromSource( proxyIndex.column() );
723 
724  if ( col == -1 )
725  col = 0;
726 
727  return index( proxyIndex.row(), col, proxyIndex.parent() );
728 }
729 
730 Qt::ItemFlags QgsAttributeTableFilterModel::flags( const QModelIndex &index ) const
731 {
732  // Handle the action column flags here, the master model doesn't know it
733  if ( mapColumnToSource( index.column() ) == -1 )
734  return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
735 
736  const QModelIndex source_index = mapToSource( index );
737  return masterModel()->flags( source_index );
738 }
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ BoundingBox
Filter using a bounding box.
This is a container for configuration of the attribute table.
@ Action
This column represents an action widget.
Qt::SortOrder sortOrder() const
Gets the sort order.
QVector< QgsAttributeTableConfig::ColumnConfig > columns() const
Gets the list with all columns and their configuration.
void update(const QgsFields &fields)
Update the configuration with the given fields.
QString sortExpression() const
Gets the expression used for sorting.
bool hasSameColumns(const QgsAttributeTableConfig &other) const
Compare this configuration's columns name, type, and order to other.
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
QString sortExpression() const
The expression which is used to sort the attribute table.
FilterMode filterMode()
The current filterModel.
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
Q_DECL_DEPRECATED void extentsChanged()
Is called upon every change of the visible extents on the map canvas.
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Sort by the given column using the given order.
QgsAttributeTableFilterModel(QgsMapCanvas *canvas, QgsAttributeTableModel *sourceModel, QObject *parent=nullptr)
Make sure, the master model is already loaded, so the selection will get synchronized.
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
void setFilterMode(FilterMode filterMode)
Set the filter mode the filter will use.
int columnCount(const QModelIndex &parent) const override
void setAttributeTableConfig(const QgsAttributeTableConfig &config, bool force=false)
Set the attribute table configuration to control which fields are shown, in which order they are show...
void generateListOfVisibleFeatures()
Updates the list of currently visible features on the map canvas.
QModelIndexList fidToIndexList(QgsFeatureId fid)
void disconnectFilterModeConnections()
Disconnect the connections set for the current filterMode.
@ Type
The type of a given column.
QModelIndex fidToIndex(QgsFeatureId fid) override
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
Used by the sorting algorithm.
FilterMode
The filter mode defines how the rows should be filtered.
@ ShowFilteredList
Show only features whose ids are on the filter list. {.
@ ShowVisible
Show only visible features (depends on the map canvas)
@ ShowSelected
Show only selected features.
@ ShowInvalid
Show only features not respecting constraints (since QGIS 3.30)
@ ShowEdited
Show only features which have unsaved changes.
bool selectedOnTop()
Returns if selected features are currently shown on top.
void filterError(const QString &errorMessage)
Emitted when an error occurred while filtering features.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
Returns true if the source row will be accepted.
QModelIndex mapFromMaster(const QModelIndex &sourceIndex) const
void filterFeatures()
Updates the filtered features in the filter model.
int actionColumnIndex() const
Gets the index of the first column that contains an action widget.
void setFilterExpression(const QgsExpression &expression, const QgsExpressionContext &context)
Set the expression and the context to be stored in case of the features need to be filtered again (li...
virtual void setFilteredFeatures(const QgsFeatureIds &ids)
Specify a list of features, which the filter will accept.
QgsFeatureId rowToId(const QModelIndex &row)
Returns the feature id for a given model index.
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
QVariant data(const QModelIndex &index, int role) const override
void featuresFiltered()
Emitted when the filtering of the features has been done.
void visibleReloaded()
Emitted when the the visible features on extend are reloaded (the list is created)
@ ColumnTypeActionButton
This column shows action buttons.
@ ColumnTypeField
This column shows a field.
QgsFeatureIds filteredFeatures()
Gets a list of currently filtered feature ids.
void setSourceModel(QgsAttributeTableModel *sourceModel)
Set the attribute table model that backs this model.
void setSelectedOnTop(bool selectedOnTop)
Changes the sort order of the features.
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
void sortColumnChanged(int column, Qt::SortOrder order)
Emitted whenever the sort column is changed.
void connectFilterModeConnections(FilterMode filterMode)
Disconnect the connections set for the new filterMode.
Qt::ItemFlags flags(const QModelIndex &index) const override
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
const QgsFeatureRequest & request() const
Gets the the feature request.
Qt::ItemFlags flags(const QModelIndex &index) const override
Returns item flags for the index.
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
QString sortCacheExpression(unsigned long cacheIndex=0) const
The expression which was used to fill the sorting cache at index cacheIndex.
QgsVectorLayerCache * layerCache() const
Returns the layer cache this model uses as backend.
int extraColumns() const
Empty extra columns to announce from this model.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of columns.
QModelIndexList idToIndexList(QgsFeatureId id) const
void prefetchSortData(const QString &expression, unsigned long cacheIndex=0)
Prefetches the entire data for an expression.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
void prefetchColumnData(int column)
Caches the entire data for one column.
@ FeatureId
Get the feature id of the feature in this row.
@ Sort
Role used for sorting start here.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
QString evalErrorString() const
Returns evaluation error.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
void setDistanceUnits(Qgis::DistanceUnit unit)
Sets the desired distance units for calculations involving geomCalculator(), e.g.,...
void setAreaUnits(Qgis::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
void setGeomCalculator(const QgsDistanceArea *calc)
Sets the geometry calculator used for distance and area calculations in expressions.
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QVariant evaluate()
Evaluate the feature and return the result.
bool isValid() const
Checks if this expression is valid.
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
bool close()
Call to end the iteration.
@ ScaleDependent
Depends on scale if feature will be rendered (rule based )
Definition: qgsrenderer.h:273
@ Filter
Features may be filtered, i.e. some features may not be rendered (categorized, rule based ....
Definition: qgsrenderer.h:272
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsRectangle filterRect() const
Returns the rectangle from which features will be taken.
Qgis::FeatureRequestFlags flags() const
Returns the flags which affect how features are fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Qgis::SpatialFilterType spatialFilterType() const
Returns the spatial filter type which is currently set on this request.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
static QString filterForLayer(QgsMapCanvas *canvas, QgsVectorLayer *layer)
Constructs a filter to use for selecting features from the given layer, in order to apply filters whi...
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:93
void extentsChanged()
Emitted when the extents of the map change.
void temporalRangeChanged()
Emitted when the map canvas temporal range changes.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:81
The QgsMapSettings class contains configuration for rendering of the map.
double scale() const
Returns the calculated map scale.
const QgsMapToPixel & mapToPixel() const
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:481
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:113
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Definition: qgsrectangle.h:355
Contains information about the context of a rendering operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
void setExtent(const QgsRectangle &extent)
When rendering a map layer, calling this method sets the "clipping" extent for the layer (in the laye...
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
void setRendererScale(double scale)
Sets the renderer map scale.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
bool isFeatureAdded(QgsFeatureId id) const
Returns true if the specified feature ID has been added but not committed.
bool isFeatureAttributesChanged(QgsFeatureId id) const
Returns true if the specified feature ID has had an attribute changed but not committed.
bool isFeatureGeometryChanged(QgsFeatureId id) const
Returns true if the specified feature ID has had its geometry changed but not committed.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Emitted whenever an attribute value change is done in the edit buffer.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer.
Q_INVOKABLE QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on.
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geometry)
Emitted whenever a geometry change is done in the edit buffer.
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition: qgis.cpp:120
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugError(str)
Definition: qgslogger.h:38
Defines the configuration of a column in the attribute table.