QGIS API Documentation  2.15.0-Master (1f0fce7)
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 "qgsvectorlayer.h"
22 #include "qgsfeature.h"
23 #include "qgsmapcanvas.h"
24 #include "qgslogger.h"
25 #include "qgsrendererv2.h"
28 // Filter Model //
30 
32  : QSortFilterProxyModel( parent )
33  , mCanvas( canvas )
34  , mFilterMode( ShowAll )
35  , mSelectedOnTop( false )
36 {
37  setSourceModel( sourceModel );
38  setDynamicSortFilter( true );
40  connect( layer(), SIGNAL( selectionChanged() ), SLOT( selectionChanged() ) );
41 }
42 
43 bool QgsAttributeTableFilterModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
44 {
45  if ( mSelectedOnTop )
46  {
47  bool leftSelected = layer()->selectedFeaturesIds().contains( masterModel()->rowToId( left.row() ) );
48  bool rightSelected = layer()->selectedFeaturesIds().contains( masterModel()->rowToId( right.row() ) );
49 
50  if ( leftSelected && !rightSelected )
51  {
52  return sortOrder() == Qt::AscendingOrder;
53  }
54  else if ( rightSelected && !leftSelected )
55  {
56  return sortOrder() == Qt::DescendingOrder;
57  }
58  }
59 
62 }
63 
64 void QgsAttributeTableFilterModel::sort( int column, Qt::SortOrder order )
65 {
66  int myColumn = mColumnMapping.at( column );
67  masterModel()->prefetchColumnData( myColumn );
68  QSortFilterProxyModel::sort( myColumn, order );
69 }
70 
72 {
73  if ( mapColumnToSource( index.column() ) == -1 ) // actions
74  {
75  if ( role == TypeRole )
77  else if ( role == QgsAttributeTableModel::FeatureIdRole )
78  {
81  }
82  }
83  else if ( role == TypeRole )
84  return ColumnTypeField;
85 
86  return QSortFilterProxyModel::data( index, role );
87 }
88 
89 QVariant QgsAttributeTableFilterModel::headerData( int section, Qt::Orientation orientation, int role ) const
90 {
91  if ( orientation == Qt::Horizontal )
92  {
93  if ( mColumnMapping.at( section ) == -1 && role == Qt::DisplayRole )
94  return tr( "Actions" );
95  else
96  return QSortFilterProxyModel::headerData( section, orientation, role );
97  }
98  else
99  {
100  if ( role == Qt::DisplayRole )
101  return section + 1;
102  else
103  {
104  int sourceSection = mapToSource( index( section, ( !mColumnMapping.isEmpty() && mColumnMapping.at( 0 ) == -1 ) ? 1 : 0 ) ).row();
105  return sourceModel()->headerData( sourceSection, orientation, role );
106  }
107  }
108 }
109 
111 {
112  return mColumnMapping.indexOf( -1 );
113 }
114 
116 {
117  Q_UNUSED( parent );
118  return mColumnMapping.count();
119 }
120 
122 {
123  mConfig = config;
124  mConfig.update( layer()->fields() );
125 
126  QVector<int> newColumnMapping;
127 
128  Q_FOREACH ( const QgsAttributeTableConfig::ColumnConfig& columnConfig, mConfig.columns() )
129  {
130  // Hidden? Forget about this column
131  if ( columnConfig.hidden )
132  continue;
133 
134  // The new value for the mapping (field index or -1 for action column)
135  int newValue = ( columnConfig.type == QgsAttributeTableConfig::Action ) ? -1 : layer()->fieldNameIndex( columnConfig.name );
136  newColumnMapping << newValue;
137  }
138 
139  if ( newColumnMapping != mColumnMapping )
140  {
141  bool requiresReset = false;
142  int firstRemovedColumn = -1;
143  int removedColumnCount = 0;
144 
145  // Check if there have a contiguous set of columns have been removed or if we require a full reset
146  for ( int i = 0; i < qMin( newColumnMapping.size(), mColumnMapping.size() - removedColumnCount ); ++i )
147  {
148  if ( newColumnMapping.at( i ) == mColumnMapping.at( i + removedColumnCount ) )
149  continue;
150 
151  if ( firstRemovedColumn == -1 )
152  {
153  firstRemovedColumn = i;
154 
155  while ( i < mColumnMapping.size() - removedColumnCount && mColumnMapping.at( i + removedColumnCount ) != newColumnMapping.at( i ) )
156  {
157  ++removedColumnCount;
158  }
159  }
160  else
161  {
162  requiresReset = true;
163  break;
164  }
165  }
166 
167  // No difference found so far
168  if ( firstRemovedColumn == -1 )
169  {
170  if ( newColumnMapping.size() > mColumnMapping.size() )
171  {
172  // More columns: appended to the end
173  beginInsertColumns( QModelIndex(), mColumnMapping.size(), newColumnMapping.size() - 1 );
174  mColumnMapping = newColumnMapping;
176  }
177  else
178  {
179  // Less columns: removed from the end
180  beginRemoveColumns( QModelIndex(), newColumnMapping.size(), mColumnMapping.size() - 1 );
181  mColumnMapping = newColumnMapping;
183  }
184  }
185  else
186  {
187  if ( newColumnMapping.size() == mColumnMapping.size() - removedColumnCount )
188  {
189  beginRemoveColumns( QModelIndex(), firstRemovedColumn, firstRemovedColumn + removedColumnCount );
190  mColumnMapping = newColumnMapping;
192  }
193  else
194  {
195  requiresReset = true;
196  }
197  }
198 
199  if ( requiresReset )
200  {
201  beginResetModel();
202  mColumnMapping = newColumnMapping;
203  endResetModel();
204  }
205  }
206 
207  sort( config.sortExpression() );
208 }
209 
210 void QgsAttributeTableFilterModel::sort( QString expression, Qt::SortOrder order )
211 {
213  masterModel()->prefetchSortData( expression );
214  QSortFilterProxyModel::sort( 0, order ) ;
215 }
216 
218 {
219  return masterModel()->sortCacheExpression();
220 }
221 
223 {
224  if ( mSelectedOnTop != selectedOnTop )
225  {
226  mSelectedOnTop = selectedOnTop;
227 
228  if ( sortColumn() == -1 )
229  {
230  sort( 0 );
231  }
232  invalidate();
233  }
234 }
235 
237 {
238  mTableModel = sourceModel;
239 
240  for ( int i = 0; i < mTableModel->columnCount() - mTableModel->extraColumns(); ++i )
241  {
242  mColumnMapping.append( i );
243  }
244 
246 
247  // Disconnect any code to update columns in the parent, we handle this manually
248  disconnect( sourceModel, SIGNAL( columnsAboutToBeInserted( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsAboutToBeInserted( QModelIndex, int, int ) ) );
249  disconnect( sourceModel, SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsInserted( QModelIndex, int, int ) ) );
250  disconnect( sourceModel, SIGNAL( columnsAboutToBeRemoved( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsAboutToBeRemoved( QModelIndex, int, int ) ) );
251  disconnect( sourceModel, SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( _q_sourceColumnsRemoved( QModelIndex, int, int ) ) );
252 
253  connect( mTableModel, SIGNAL( columnsAboutToBeInserted( QModelIndex, int, int ) ), this, SLOT( onColumnsChanged() ) );
254  connect( mTableModel, SIGNAL( columnsAboutToBeRemoved( QModelIndex, int, int ) ), this, SLOT( onColumnsChanged() ) );
255 }
256 
258 {
259  return mSelectedOnTop;
260 }
261 
263 {
264  mFilteredFeatures = ids;
267 }
268 
270 {
271  QgsFeatureIds ids;
272  for ( int i = 0; i < rowCount(); ++i )
273  {
274  QModelIndex row = index( i, 0 );
275  ids << rowToId( row );
276  }
277  return ids;
278 }
279 
281 {
282  if ( filterMode != mFilterMode )
283  {
284  if ( filterMode == ShowVisible )
285  {
286  connect( mCanvas, SIGNAL( extentsChanged() ), this, SLOT( extentsChanged() ) );
288  }
289  else
290  {
291  disconnect( mCanvas, SIGNAL( extentsChanged() ), this, SLOT( extentsChanged() ) );
292  }
293 
294  if ( filterMode == ShowSelected )
295  {
297  }
298 
299  mFilterMode = filterMode;
301  }
302 }
303 
304 bool QgsAttributeTableFilterModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
305 {
306  Q_UNUSED( sourceParent );
307  switch ( mFilterMode )
308  {
309  case ShowAll:
310  return true;
311 
312  case ShowFilteredList:
313  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
314 
315  case ShowSelected:
316  return layer()->selectedFeaturesIds().isEmpty() || layer()->selectedFeaturesIds().contains( masterModel()->rowToId( sourceRow ) );
317 
318  case ShowVisible:
319  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
320 
321  case ShowEdited:
322  {
323  QgsVectorLayerEditBuffer* editBuffer = layer()->editBuffer();
324  if ( editBuffer )
325  {
326  const QList<QgsFeatureId> addedFeatures = editBuffer->addedFeatures().keys();
327  const QList<QgsFeatureId> changedFeatures = editBuffer->changedAttributeValues().keys();
328  const QList<QgsFeatureId> changedGeometries = editBuffer->changedGeometries().keys();
329  const QgsFeatureId fid = masterModel()->rowToId( sourceRow );
330  return addedFeatures.contains( fid ) || changedFeatures.contains( fid ) || changedGeometries.contains( fid );
331  }
332  return false;
333  }
334 
335  default:
336  Q_ASSERT( false ); // In debug mode complain
337  return true; // In release mode accept row
338  }
339  // returns are handled in their respective case statement above
340 }
341 
343 {
346 }
347 
348 void QgsAttributeTableFilterModel::selectionChanged()
349 {
350  if ( ShowSelected == mFilterMode )
351  {
354  }
355  else if ( mSelectedOnTop )
356  {
357  sort( sortColumn(), sortOrder() );
358  invalidate();
359  }
360 }
361 
362 void QgsAttributeTableFilterModel::onColumnsChanged()
363 {
364  setAttributeTableConfig( mConfig );
365 }
366 
367 int QgsAttributeTableFilterModel::mapColumnToSource( int column ) const
368 {
369  if ( mColumnMapping.isEmpty() )
370  return column;
371  if ( column < 0 || column >= mColumnMapping.size() )
372  return -1;
373  else
374  return mColumnMapping.at( column );
375 }
376 
378 {
379  if ( !layer() )
380  return;
381 
382  bool filter = false;
383  QgsRectangle rect = mCanvas->mapSettings().mapToLayerCoordinates( layer(), mCanvas->extent() );
384  QgsRenderContext renderContext;
388  QgsFeatureRendererV2* renderer = layer()->rendererV2();
389 
390  mFilteredFeatures.clear();
391 
392  if ( !renderer )
393  {
394  QgsDebugMsg( "Cannot get renderer" );
395  return;
396  }
397 
398  const QgsMapSettings& ms = mCanvas->mapSettings();
399  if ( !layer()->isInScaleRange( ms.scale() ) )
400  {
401  QgsDebugMsg( "Out of scale limits" );
402  }
403  else
404  {
405  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
406  {
407  // setup scale
408  // mapRenderer()->renderContext()->scale is not automaticaly updated when
409  // render extent changes (because it's scale is used to identify if changed
410  // since last render) -> use local context
411  renderContext.setExtent( ms.visibleExtent() );
412  renderContext.setMapToPixel( ms.mapToPixel() );
413  renderContext.setRendererScale( ms.scale() );
414  }
415 
416  filter = renderer && renderer->capabilities() & QgsFeatureRendererV2::Filter;
417  }
418 
419  renderer->startRender( renderContext, layer()->fields() );
420 
421  QgsFeatureRequest r( masterModel()->request() );
422  if ( !r.filterRect().isNull() )
423  {
424  r.setFilterRect( r.filterRect().intersect( &rect ) );
425  }
426  else
427  {
428  r.setFilterRect( rect );
429  }
431 
432  QgsFeature f;
433 
434  while ( features.nextFeature( f ) )
435  {
436  renderContext.expressionContext().setFeature( f );
437  if ( !filter || renderer->willRenderFeature( f, renderContext ) )
438  {
439  mFilteredFeatures << f.id();
440  }
441 #if 0
442  if ( t.elapsed() > 5000 )
443  {
444  bool cancel = false;
445  emit progress( i, cancel );
446  if ( cancel )
447  break;
448 
449  t.restart();
450  }
451 #endif
452  }
453 
454  features.close();
455 
456  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
457  {
458  renderer->stopRender( renderContext );
459  }
460 }
461 
463 {
464  return masterModel()->rowToId( mapToSource( row ).row() );
465 }
466 
468 {
469  return mapFromMaster( masterModel()->idToIndex( fid ) );
470 }
471 
473 {
474  QModelIndexList indexes;
475  Q_FOREACH ( const QModelIndex& idx, masterModel()->idToIndexList( fid ) )
476  {
477  indexes.append( mapFromMaster( idx ) );
478  }
479 
480  return indexes;
481 }
482 
484 {
485  if ( !proxyIndex.isValid() )
486  return QModelIndex();
487 
488  int sourceColumn = mapColumnToSource( proxyIndex.column() );
489 
490  // For the action column there is no matching column in the source model, just return the first one
491  // so we are still able to query for the feature id, the feature...
492  if ( sourceColumn == -1 )
493  sourceColumn = 0;
494 
495  return QSortFilterProxyModel::mapToSource( index( proxyIndex.row(), sourceColumn, proxyIndex.parent() ) );
496 }
497 
499 {
500  QModelIndex proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
501 
502  if ( proxyIndex.column() < 0 )
503  return QModelIndex();
504 
505  return index( proxyIndex.row(), mapColumnToSource( proxyIndex.column() ), proxyIndex.parent() );
506 }
507 
509 {
510  // Handle the action column flags here, the master model doesn't know it
511  if ( mapColumnToSource( index.column() ) == -1 )
512  return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
513 
514  QModelIndex source_index = mapToSource( index );
515  return masterModel()->flags( source_index );
516 }
517 
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
void generateListOfVisibleFeatures()
Updates the list of currently visible features on the map canvas.
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
const QgsGeometryMap & changedGeometries()
Changed geometries which are not commited.
QgsFeatureId rowToId(const QModelIndex &row)
Returns the feature id for a given model index.
Wrapper for iterator of features from vector data provider or vector layer.
virtual QVariant data(const QModelIndex &index, int role) const override
void setSortRole(int role)
A rectangle specified with double values.
Definition: qgsrectangle.h:35
void update(const QgsFields &fields)
Update the configuration with the given fields.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
Returns true if the source row will be accepted.
bool selectedOnTop()
Returns if selected features are currently shown on top.
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table configuration to control which fields are shown, in which order they are show...
double scale() const
Return the calculated scale of the map.
void setSelectedOnTop(bool selectedOnTop)
Changes the sort order of the features.
virtual void sort(int column, Qt::SortOrder order)
int actionColumnIndex() const
Get the index of the first column that contains an action widget.
void setFilterMode(FilterMode filterMode)
Set the filter mode the filter will use.
void append(const T &value)
const QgsRectangle & filterRect() const
Get the rectangle from which features will be taken.
virtual void setSourceModel(QAbstractItemModel *sourceModel)
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
int extraColumns() const
Empty extra columns to announce from this model.
int indexOf(const T &value, int from) const
void setRendererScale(double scale)
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
Used by the sorting algorithm.
const QgsChangedAttributesMap & changedAttributeValues()
Changed attributes values which are not commited.
bool isNull() const
test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
void columnsRemoved(const QModelIndex &parent, int start, int end)
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
This column represents an action widget.
const QgsMapToPixel & mapToPixel() const
depends on scale if feature will be rendered (rule based )
QString sortCacheExpression() const
The expression which was used to fill the sorting cache.
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
Show only visible features (depends on the map canvas)
QgsPoint mapToLayerCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from output CRS to layer&#39;s CRS
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual Q_DECL_DEPRECATED bool willRenderFeature(QgsFeature &feat)
Returns whether the renderer will render a feature or not.
QString tr(const char *sourceText, const char *disambiguation, int n)
void setExtent(const QgsRectangle &extent)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:109
virtual int rowCount(const QModelIndex &parent) const
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:269
QgsAttributeTableFilterModel(QgsMapCanvas *canvas, QgsAttributeTableModel *sourceModel, QObject *parent=nullptr)
Make sure, the master model is already loaded, so the selection will get synchronized.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
Needs to be called when a new render cycle is started.
virtual void setFilteredFeatures(const QgsFeatureIds &ids)
Specify a list of features, which the filter will accept.
The QgsMapSettings class contains configuration for rendering of the map.
QString sortExpression() const
Get the expression used for sorting.
virtual void stopRender(QgsRenderContext &context)=0
Needs to be called when a render cycle has finished to clean up.
Get the feature id of the feature in this row.
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
QList< Key > keys() const
bool isValid() const
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
FilterMode filterMode()
The current filterModel.
const QgsFeatureIds & selectedFeaturesIds() const
Return reference to identifiers of selected features.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of columns.
FilterMode
The filter mode defines how the rows should be filtered.
int row() const
bool hidden
Flag that controls if the column is hidden.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void beginRemoveColumns(const QModelIndex &parent, int first, int last)
void setDynamicSortFilter(bool enable)
virtual QVariant data(const QModelIndex &index, int role) const =0
Show only features which have unsaved changes.
QModelIndex parent() const
void columnsInserted(const QModelIndex &parent, int start, int end)
QgsVectorLayerCache * layerCache() const
Returns the layer cache this model uses as backend.
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const
QString name
The name of the attribute if this column represents a field.
void setSourceModel(QgsAttributeTableModel *sourceModel)
Set the attribute table model that backs this model.
void extentsChanged()
Is called upon every change of the visible extents on the map canvas.
void columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
bool contains(const T &value) const
QgsExpressionContext & expressionContext()
Gets the expression context.
Show only features whose ids are on the filter list. {.
bool contains(const T &value) const
QVector< ColumnConfig > columns() const
Get the list with all columns and their configuration.
const QgsFeatureMap & addedFeatures()
New features which are not commited.
const T & at(int i) const
Contains information about the context of a rendering operation.
QAbstractItemModel * sourceModel() const
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
QModelIndex mapFromMaster(const QModelIndex &sourceIndex) const
Qt::SortOrder sortOrder() const
QVariant data(int role) const
virtual void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Sort by the given column using the given order.
QString sortExpression() const
The expression which is used to sort the attribute table.
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
bool isEmpty() const
QgsRectangle intersect(const QgsRectangle *rect) const
return the intersection with the given rectangle
int columnCount(const QModelIndex &parent) const override
int count(const T &value) const
void setMapToPixel(const QgsMapToPixel &mtp)
int column() const
bool isEmpty() const
Defines the configuration of a column in the attribute table.
qint64 QgsFeatureId
Definition: qgsfeature.h:31
QgsFeatureIds filteredFeatures()
Get a list of currently filtered feature ids.
QgsRectangle extent() const
Returns the current zoom exent of the map canvas.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
virtual int capabilities()
returns bitwise OR-ed capabilities of the renderer
bool nextFeature(QgsFeature &f)
features may be filtered, i.e. some features may not be rendered (categorized, rule based ...
void clear()
This is a container for configuration of the attribute table.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
int size() const
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
QModelIndexList fidToIndexList(QgsFeatureId fid)
int sortColumn() const
void beginInsertColumns(const QModelIndex &parent, int first, int last)
void prefetchColumnData(int column)
Caches the entire data for one column.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rect)
Set rectangle from which features will be taken.
void prefetchSortData(const QString &expression)
Prefetches the entire data for one expression.
virtual QVariant data(const QModelIndex &index, int role) const
Qt::ItemFlags flags(const QModelIndex &index) const override
Returns item flags for the index.
QModelIndex fidToIndex(QgsFeatureId fid) override
void columnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
virtual Qt::ItemFlags flags(const QModelIndex &index) const override
typedef ItemFlags