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