QGIS API Documentation  3.23.0-Master (eb871beae0)
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 
18 #include "qgis.h"
20 #include "qgsattributetablemodel.h"
21 #include "qgsfeatureiterator.h"
22 #include "qgsvectorlayer.h"
24 #include "qgsfeature.h"
25 #include "qgsmapcanvas.h"
26 #include "qgslogger.h"
27 #include "qgsrenderer.h"
30 #include "qgsapplication.h"
31 #include "qgsvectorlayercache.h"
32 #include "qgsrendercontext.h"
33 
35 // Filter Model //
37 
39  : QSortFilterProxyModel( parent )
40  , mCanvas( canvas )
41 {
42  setSourceModel( sourceModel );
43  setDynamicSortFilter( true );
44  setSortRole( QgsAttributeTableModel::SortRole );
45  connect( layer(), &QgsVectorLayer::selectionChanged, this, &QgsAttributeTableFilterModel::selectionChanged );
46 
47  mReloadVisibleTimer.setSingleShot( true );
48  connect( &mReloadVisibleTimer, &QTimer::timeout, this, &QgsAttributeTableFilterModel::reloadVisible );
49  mFilterFeaturesTimer.setSingleShot( true );
50  connect( &mFilterFeaturesTimer, &QTimer::timeout, this, &QgsAttributeTableFilterModel::filterFeatures );
51 }
52 
53 bool QgsAttributeTableFilterModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
54 {
55  if ( mSelectedOnTop )
56  {
57  const bool leftSelected = layer()->selectedFeatureIds().contains( masterModel()->rowToId( left.row() ) );
58  const bool rightSelected = layer()->selectedFeatureIds().contains( masterModel()->rowToId( right.row() ) );
59 
60  if ( leftSelected && !rightSelected )
61  {
62  return sortOrder() == Qt::AscendingOrder;
63  }
64  else if ( rightSelected && !leftSelected )
65  {
66  return sortOrder() == Qt::DescendingOrder;
67  }
68  }
69 
70  if ( mTableModel->sortCacheExpression().isEmpty() )
71  {
72  //shortcut when no sort order set
73  return false;
74  }
75 
77  right.data( QgsAttributeTableModel::SortRole ) );
78 }
79 
80 void QgsAttributeTableFilterModel::sort( int column, Qt::SortOrder order )
81 {
82  if ( order != Qt::AscendingOrder && order != Qt::DescendingOrder )
83  order = Qt::AscendingOrder;
84  if ( column < 0 || column >= mColumnMapping.size() )
85  {
86  sort( QString() );
87  }
88  else
89  {
90  const int myColumn = mColumnMapping.at( column );
91  masterModel()->prefetchColumnData( myColumn );
92  QSortFilterProxyModel::sort( myColumn, order );
93  }
94  emit sortColumnChanged( column, order );
95 }
96 
97 QVariant QgsAttributeTableFilterModel::data( const QModelIndex &index, int role ) const
98 {
99  if ( mapColumnToSource( index.column() ) == -1 ) // actions
100  {
101  if ( role == TypeRole )
102  return ColumnTypeActionButton;
103  else if ( role == QgsAttributeTableModel::FeatureIdRole )
104  {
105  const QModelIndex fieldIndex = QSortFilterProxyModel::mapToSource( QSortFilterProxyModel::index( index.row(), 0, index.parent() ) );
106  return sourceModel()->data( fieldIndex, QgsAttributeTableModel::FeatureIdRole );
107  }
108  }
109  else if ( role == TypeRole )
110  return ColumnTypeField;
111 
112  return QSortFilterProxyModel::data( index, role );
113 }
114 
115 QVariant QgsAttributeTableFilterModel::headerData( int section, Qt::Orientation orientation, int role ) const
116 {
117  if ( orientation == Qt::Horizontal )
118  {
119  if ( mColumnMapping.at( section ) == -1 && role == Qt::DisplayRole )
120  return tr( "Actions" );
121  else
122  return QSortFilterProxyModel::headerData( section, orientation, role );
123  }
124  else
125  {
126  if ( role == Qt::DisplayRole )
127  return section + 1;
128  else
129  {
130  const int sourceSection = mapToSource( index( section, ( !mColumnMapping.isEmpty() && mColumnMapping.at( 0 ) == -1 ) ? 1 : 0 ) ).row();
131  return sourceModel()->headerData( sourceSection, orientation, role );
132  }
133  }
134 }
135 
137 {
138  return mColumnMapping.indexOf( -1 );
139 }
140 
141 int QgsAttributeTableFilterModel::columnCount( const QModelIndex &parent ) const
142 {
143  Q_UNUSED( parent )
144  return mColumnMapping.count();
145 }
146 
148 {
149  const QgsAttributeTableConfig oldConfig = mConfig;
150  mConfig = config;
151  mConfig.update( layer()->fields() );
152 
153  if ( !force && mConfig.hasSameColumns( oldConfig ) )
154  {
155  return;
156  }
157 
158  QVector<int> newColumnMapping;
159  const auto constColumns = mConfig.columns();
160  for ( const QgsAttributeTableConfig::ColumnConfig &columnConfig : constColumns )
161  {
162  // Hidden? Forget about this column
163  if ( columnConfig.hidden )
164  continue;
165 
166  // The new value for the mapping (field index or -1 for action column)
167  const int newValue = ( columnConfig.type == QgsAttributeTableConfig::Action ) ? -1 : layer()->fields().lookupField( columnConfig.name );
168  newColumnMapping << newValue;
169  }
170 
171  if ( newColumnMapping != mColumnMapping )
172  {
173  bool requiresReset = false;
174  int firstRemovedColumn = -1;
175  int removedColumnCount = 0;
176 
177  // Check if there have a contiguous set of columns have been removed or if we require a full reset
178  for ( int i = 0; i < std::min( newColumnMapping.size(), mColumnMapping.size() - removedColumnCount ); ++i )
179  {
180  if ( newColumnMapping.at( i ) == mColumnMapping.at( i + removedColumnCount ) )
181  continue;
182 
183  if ( firstRemovedColumn == -1 )
184  {
185  firstRemovedColumn = i;
186 
187  while ( i < mColumnMapping.size() - removedColumnCount && mColumnMapping.at( i + removedColumnCount ) != newColumnMapping.at( i ) )
188  {
189  ++removedColumnCount;
190  }
191  }
192  else
193  {
194  requiresReset = true;
195  break;
196  }
197  }
198 
199  // No difference found so far
200  if ( firstRemovedColumn == -1 )
201  {
202  if ( newColumnMapping.size() > mColumnMapping.size() )
203  {
204  // More columns: appended to the end
205  beginInsertColumns( QModelIndex(), mColumnMapping.size(), newColumnMapping.size() - 1 );
206  mColumnMapping = newColumnMapping;
207  endInsertColumns();
208  }
209  else
210  {
211  // Less columns: removed from the end
212  beginRemoveColumns( QModelIndex(), newColumnMapping.size(), mColumnMapping.size() - 1 );
213  mColumnMapping = newColumnMapping;
214  endRemoveColumns();
215  }
216  }
217  else
218  {
219  if ( newColumnMapping.size() == mColumnMapping.size() - removedColumnCount )
220  {
221  //the amount of removed column in the model need to be equal removedColumnCount
222  beginRemoveColumns( QModelIndex(), firstRemovedColumn, firstRemovedColumn + removedColumnCount - 1 );
223  mColumnMapping = newColumnMapping;
224  endRemoveColumns();
225  }
226  else
227  {
228  requiresReset = true;
229  }
230  }
231 
232  if ( requiresReset )
233  {
234  beginResetModel();
235  mColumnMapping = newColumnMapping;
236  endResetModel();
237  }
238  }
239 
240  if ( !config.sortExpression().isEmpty() )
241  sort( config.sortExpression(), config.sortOrder() );
242 }
243 
245 {
246  mFilterExpression = expression;
247  mFilterExpressionContext = context;
248 }
249 
250 void QgsAttributeTableFilterModel::sort( const QString &expression, Qt::SortOrder order )
251 {
252  if ( order != Qt::AscendingOrder && order != Qt::DescendingOrder )
253  order = Qt::AscendingOrder;
254 
255  QSortFilterProxyModel::sort( -1 );
256  masterModel()->prefetchSortData( expression );
257  QSortFilterProxyModel::sort( 0, order );
258 }
259 
261 {
262  return masterModel()->sortCacheExpression();
263 }
264 
266 {
267  if ( mSelectedOnTop != selectedOnTop )
268  {
269  mSelectedOnTop = selectedOnTop;
270  int column = sortColumn();
271  Qt::SortOrder order = sortOrder();
272 
273  // set default sort values if they are not correctly set
274  if ( column < 0 )
275  column = 0;
276 
277  if ( order != Qt::AscendingOrder && order != Qt::DescendingOrder )
278  order = Qt::AscendingOrder;
279 
280  sort( 0, Qt::AscendingOrder );
281  invalidate();
282  }
283 }
284 
286 {
287  mTableModel = sourceModel;
288 
289  for ( int i = 0; i < mTableModel->columnCount() - mTableModel->extraColumns(); ++i )
290  {
291  mColumnMapping.append( i );
292  }
293 
294  QSortFilterProxyModel::setSourceModel( sourceModel );
295 
296  // Disconnect any code to update columns in the parent, we handle this manually
297  disconnect( mTableModel, SIGNAL( columnsAboutToBeInserted( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsAboutToBeInserted( QModelIndex, int, int ) ) );
298  disconnect( mTableModel, SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsInserted( QModelIndex, int, int ) ) );
299  disconnect( mTableModel, SIGNAL( columnsAboutToBeRemoved( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsAboutToBeRemoved( QModelIndex, int, int ) ) );
300  disconnect( mTableModel, SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsRemoved( QModelIndex, int, int ) ) );
301  // The following connections are needed in order to keep the filter model in sync, see: regression #15974
302  connect( mTableModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &QgsAttributeTableFilterModel::onColumnsChanged );
303  connect( mTableModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &QgsAttributeTableFilterModel::onColumnsChanged );
304 
305 }
306 
308 {
309  return mSelectedOnTop;
310 }
311 
313 {
314  mFilteredFeatures = ids;
316  invalidateFilter();
317 }
318 
320 {
321  QgsFeatureIds ids;
322  ids.reserve( rowCount() );
323  for ( int i = 0; i < rowCount(); ++i )
324  {
325  const QModelIndex row = index( i, 0 );
326  ids << rowToId( row );
327  }
328  return ids;
329 }
330 
332 {
333  if ( filterMode != mFilterMode )
334  {
337  mFilterMode = filterMode;
338  invalidate();
339  }
340 }
341 
343 {
344  // cleanup existing connections
345  switch ( mFilterMode )
346  {
347  case ShowVisible:
348  disconnect( mCanvas, &QgsMapCanvas::extentsChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
349  disconnect( mCanvas, &QgsMapCanvas::temporalRangeChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
350  disconnect( layer(), &QgsVectorLayer::featureAdded, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
351  disconnect( layer(), &QgsVectorLayer::geometryChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
352  break;
353  case ShowAll:
354  case ShowEdited:
355  case ShowSelected:
356  break;
357  case ShowFilteredList:
358  disconnect( layer(), &QgsVectorLayer::featureAdded, this, &QgsAttributeTableFilterModel::startTimedFilterFeatures );
359  disconnect( layer(), &QgsVectorLayer::attributeValueChanged, this, &QgsAttributeTableFilterModel::onAttributeValueChanged );
360  disconnect( layer(), &QgsVectorLayer::geometryChanged, this, &QgsAttributeTableFilterModel::onGeometryChanged );
361  break;
362  }
363 }
364 
366 {
367  // setup new connections
368  switch ( filterMode )
369  {
370  case ShowVisible:
371  connect( mCanvas, &QgsMapCanvas::extentsChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
372  connect( mCanvas, &QgsMapCanvas::temporalRangeChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
373  connect( layer(), &QgsVectorLayer::featureAdded, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
374  connect( layer(), &QgsVectorLayer::geometryChanged, this, &QgsAttributeTableFilterModel::startTimedReloadVisible );
376  break;
377  case ShowAll:
378  case ShowEdited:
379  case ShowSelected:
380  break;
381  case ShowFilteredList:
382  connect( layer(), &QgsVectorLayer::featureAdded, this, &QgsAttributeTableFilterModel::startTimedFilterFeatures );
383  connect( layer(), &QgsVectorLayer::attributeValueChanged, this, &QgsAttributeTableFilterModel::onAttributeValueChanged );
384  connect( layer(), &QgsVectorLayer::geometryChanged, this, &QgsAttributeTableFilterModel::onGeometryChanged );
385  break;
386  }
387 }
388 
389 bool QgsAttributeTableFilterModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
390 {
391  Q_UNUSED( sourceParent )
392  switch ( mFilterMode )
393  {
394  case ShowAll:
395  return true;
396 
397  case ShowFilteredList:
398  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
399 
400  case ShowSelected:
401  return layer()->selectedFeatureIds().contains( masterModel()->rowToId( sourceRow ) );
402 
403  case ShowVisible:
404  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
405 
406  case ShowEdited:
407  {
408  QgsVectorLayerEditBuffer *editBuffer = layer()->editBuffer();
409  if ( editBuffer )
410  {
411  const QgsFeatureId fid = masterModel()->rowToId( sourceRow );
412 
413  if ( editBuffer->isFeatureAdded( fid ) )
414  return true;
415 
416  if ( editBuffer->isFeatureAttributesChanged( fid ) )
417  return true;
418 
419  if ( editBuffer->isFeatureGeometryChanged( fid ) )
420  return true;
421 
422  return false;
423  }
424  return false;
425  }
426 
427  default:
428  Q_ASSERT( false ); // In debug mode complain
429  return true; // In release mode accept row
430  }
431  // returns are handled in their respective case statement above
432 }
433 
435 {
436  reloadVisible();
437 }
438 
439 void QgsAttributeTableFilterModel::reloadVisible()
440 {
442  invalidateFilter();
443  emit visibleReloaded();
444 }
445 
446 void QgsAttributeTableFilterModel::onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value )
447 {
448  Q_UNUSED( fid );
449  Q_UNUSED( value );
450 
451  if ( mFilterExpression.referencedAttributeIndexes( layer()->fields() ).contains( idx ) )
452  {
453  startTimedFilterFeatures();
454  }
455 }
456 
457 void QgsAttributeTableFilterModel::onGeometryChanged()
458 {
459  if ( mFilterExpression.needsGeometry() )
460  {
461  startTimedFilterFeatures();
462  }
463 }
464 
465 void QgsAttributeTableFilterModel::startTimedReloadVisible()
466 {
467  mReloadVisibleTimer.start( 10 );
468 }
469 
470 void QgsAttributeTableFilterModel::startTimedFilterFeatures()
471 {
472  mFilterFeaturesTimer.start( 10 );
473 }
474 
476 {
477  if ( !mFilterExpression.isValid() )
478  return;
479 
481  QgsDistanceArea distanceArea;
482 
483  distanceArea.setSourceCrs( mTableModel->layer()->crs(), QgsProject::instance()->transformContext() );
484  distanceArea.setEllipsoid( QgsProject::instance()->ellipsoid() );
485 
486  const bool fetchGeom = mFilterExpression.needsGeometry();
487 
488  QApplication::setOverrideCursor( Qt::WaitCursor );
489 
490  mFilterExpression.setGeomCalculator( &distanceArea );
491  mFilterExpression.setDistanceUnits( QgsProject::instance()->distanceUnits() );
492  mFilterExpression.setAreaUnits( QgsProject::instance()->areaUnits() );
493  QgsFeatureRequest request( mTableModel->request() );
494  request.setSubsetOfAttributes( mFilterExpression.referencedColumns(), mTableModel->layer()->fields() );
495  if ( !fetchGeom )
496  {
498  }
499  else
500  {
501  // force geometry extraction if the filter requests it
502  request.setFlags( request.flags() & ~QgsFeatureRequest::NoGeometry );
503  }
504  QgsFeatureIterator featIt = mTableModel->layer()->getFeatures( request );
505 
506  QgsFeature f;
507 
508  // Record the first evaluation error
509  QString error;
510 
511  while ( featIt.nextFeature( f ) )
512  {
513  mFilterExpressionContext.setFeature( f );
514  if ( mFilterExpression.evaluate( &mFilterExpressionContext ).toInt() != 0 )
515  filteredFeatures << f.id();
516 
517  // check if there were errors during evaluating
518  if ( mFilterExpression.hasEvalError() && error.isEmpty() )
519  {
520  error = mFilterExpression.evalErrorString( );
521  }
522  }
523 
524  featIt.close();
525 
527 
528  QApplication::restoreOverrideCursor();
529 
530  emit featuresFiltered();
531 
532  if ( ! error.isEmpty() )
533  {
534  emit filterError( error );
535  }
536 
537 }
538 
539 
540 void QgsAttributeTableFilterModel::selectionChanged()
541 {
542  if ( ShowSelected == mFilterMode )
543  {
544  invalidateFilter();
545  }
546  else if ( mSelectedOnTop )
547  {
548  invalidate();
549  }
550 }
551 
552 void QgsAttributeTableFilterModel::onColumnsChanged()
553 {
554  setAttributeTableConfig( mConfig );
555 }
556 
557 int QgsAttributeTableFilterModel::mapColumnToSource( int column ) const
558 {
559  if ( mColumnMapping.isEmpty() )
560  return column;
561  if ( column < 0 || column >= mColumnMapping.size() )
562  return -1;
563  else
564  return mColumnMapping.at( column );
565 }
566 
567 int QgsAttributeTableFilterModel::mapColumnFromSource( int column ) const
568 {
569  if ( mColumnMapping.isEmpty() )
570  return column;
571  else
572  return mColumnMapping.indexOf( column );
573 }
574 
576 {
577  if ( !layer() )
578  return;
579 
580  bool filter = false;
581  const QgsRectangle rect = mCanvas->mapSettings().mapToLayerCoordinates( layer(), mCanvas->extent() );
582  QgsRenderContext renderContext;
584 
585  mFilteredFeatures.clear();
586  if ( !layer()->renderer() )
587  {
588  QgsDebugMsg( QStringLiteral( "Cannot get renderer" ) );
589  return;
590  }
591 
592  std::unique_ptr< QgsFeatureRenderer > renderer( layer()->renderer()->clone() );
593 
594  const QgsMapSettings &ms = mCanvas->mapSettings();
595  if ( !layer()->isInScaleRange( ms.scale() ) )
596  {
597  QgsDebugMsg( QStringLiteral( "Out of scale limits" ) );
598  }
599  else
600  {
601  if ( renderer->capabilities() & QgsFeatureRenderer::ScaleDependent )
602  {
603  // setup scale
604  // mapRenderer()->renderContext()->scale is not automatically updated when
605  // render extent changes (because it's scale is used to identify if changed
606  // since last render) -> use local context
607  renderContext.setExtent( ms.visibleExtent() );
608  renderContext.setMapToPixel( ms.mapToPixel() );
609  renderContext.setRendererScale( ms.scale() );
610  }
611 
612  filter = renderer->capabilities() & QgsFeatureRenderer::Filter;
613  }
614 
615  renderer->startRender( renderContext, layer()->fields() );
616 
617  QgsFeatureRequest r( masterModel()->request() );
619  {
620  r.setFilterRect( r.filterRect().intersect( rect ) );
621  }
622  else
623  {
624  r.setFilterRect( rect );
625  }
626 
627  if ( mCanvas->mapSettings().isTemporal() )
628  {
629  if ( !layer()->temporalProperties()->isVisibleInTemporalRange( mCanvas->mapSettings().temporalRange() ) )
630  return;
631 
632  QgsVectorLayerTemporalContext temporalContext;
633  temporalContext.setLayer( layer() );
634  const QString temporalFilter = qobject_cast< const QgsVectorLayerTemporalProperties * >( layer()->temporalProperties() )->createFilterString( temporalContext, mCanvas->mapSettings().temporalRange() );
635  if ( !temporalFilter.isEmpty() )
636  r.setFilterExpression( temporalFilter );
637  }
638 
640 
641  QgsFeature f;
642 
643  while ( features.nextFeature( f ) )
644  {
645  renderContext.expressionContext().setFeature( f );
646  if ( !filter || renderer->willRenderFeature( f, renderContext ) )
647  {
648  mFilteredFeatures << f.id();
649  }
650 #if 0
651  if ( t.elapsed() > 5000 )
652  {
653  bool cancel = false;
654  emit progress( i, cancel );
655  if ( cancel )
656  break;
657 
658  t.restart();
659  }
660 #endif
661  }
662 
663  features.close();
664 
665  if ( renderer->capabilities() & QgsFeatureRenderer::ScaleDependent )
666  {
667  renderer->stopRender( renderContext );
668  }
669 }
670 
672 {
673  return masterModel()->rowToId( mapToSource( row ).row() );
674 }
675 
677 {
678  return mapFromMaster( masterModel()->idToIndex( fid ) );
679 }
680 
682 {
683  QModelIndexList indexes;
684  const auto constIdToIndexList = masterModel()->idToIndexList( fid );
685  for ( const QModelIndex &idx : constIdToIndexList )
686  {
687  indexes.append( mapFromMaster( idx ) );
688  }
689 
690  return indexes;
691 }
692 
693 QModelIndex QgsAttributeTableFilterModel::mapToSource( const QModelIndex &proxyIndex ) const
694 {
695  if ( !proxyIndex.isValid() )
696  return QModelIndex();
697 
698  int sourceColumn = mapColumnToSource( proxyIndex.column() );
699 
700  // For the action column there is no matching column in the source model, just return the first one
701  // so we are still able to query for the feature id, the feature...
702  if ( sourceColumn == -1 )
703  sourceColumn = 0;
704 
705  return QSortFilterProxyModel::mapToSource( index( proxyIndex.row(), sourceColumn, proxyIndex.parent() ) );
706 }
707 
708 QModelIndex QgsAttributeTableFilterModel::mapFromSource( const QModelIndex &sourceIndex ) const
709 {
710  const QModelIndex proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
711 
712  if ( proxyIndex.column() < 0 )
713  return QModelIndex();
714 
715  int col = mapColumnFromSource( proxyIndex.column() );
716 
717  if ( col == -1 )
718  col = 0;
719 
720  return index( proxyIndex.row(), col, proxyIndex.parent() );
721 }
722 
723 Qt::ItemFlags QgsAttributeTableFilterModel::flags( const QModelIndex &index ) const
724 {
725  // Handle the action column flags here, the master model doesn't know it
726  if ( mapColumnToSource( index.column() ) == -1 )
727  return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
728 
729  const QModelIndex source_index = mapToSource( index );
730  return masterModel()->flags( source_index );
731 }
@ 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
@ TypeRole
The type of a given column.
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.
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.
@ 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.
@ SortRole
Role used for sorting start here.
@ FeatureIdRole
Get the feature id of the feature in this row.
void prefetchColumnData(int column)
Caches the entire data for one column.
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.
void setDistanceUnits(QgsUnitTypes::DistanceUnit unit)
Sets the desired distance units for calculations involving geomCalculator(), e.g.,...
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
void setAreaUnits(QgsUnitTypes::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)
@ ScaleDependent
Depends on scale if feature will be rendered (rule based )
Definition: qgsrenderer.h:266
@ Filter
Features may be filtered, i.e. some features may not be rendered (categorized, rule based ....
Definition: qgsrenderer.h:265
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsRectangle filterRect() const
Returns the rectangle from which features will be taken.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
Flags 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.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
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:344
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
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:79
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:468
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:107
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:333
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.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
bool isTemporal() const
Returns true if the object's temporal range is enabled, and the object will be filtered when renderin...
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.
Encapsulates the context in which a QgsVectorLayer's temporal capabilities will be applied.
void setLayer(QgsVectorLayer *layer)
Sets the associated layer.
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:127
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 QgsDebugMsg(str)
Definition: qgslogger.h:38
Defines the configuration of a column in the attribute table.