50 : QAbstractTableModel( parent )
51 , mLayerCache( layerCache )
60 mFeat.
setId( std::numeric_limits<int>::min() );
62 if ( !
layer()->isSpatial() )
82 bool QgsAttributeTableModel::loadFeatureAtId(
QgsFeatureId fid )
const 86 if ( fid == std::numeric_limits<int>::min() )
105 void QgsAttributeTableModel::featuresDeleted(
const QgsFeatureIds &fids )
109 const auto constFids = fids;
112 QgsDebugMsgLevel( QStringLiteral(
"(%2) fid: %1, size: %3" ).arg( fid ).arg( mFeatureRequest.
filterType() ).arg( mIdRowMap.size() ), 4 );
119 std::sort( rows.begin(), rows.end() );
123 int currentRowCount = 0;
127 const auto constRows = rows;
128 for (
int row : constRows )
131 qDebug() <<
"Row: " << row <<
", begin " << beginRow <<
", last " << lastRow <<
", current " << currentRowCount <<
", removed " << removedRows;
138 if ( row != lastRow + 1 && lastRow != -1 )
140 if ( rows.count() > 100 && currentRowCount < 10 )
145 removeRows( beginRow - removedRows, currentRowCount );
148 removedRows += currentRowCount;
158 removeRows( beginRow - removedRows, currentRowCount );
166 if ( row < 0 || count < 1 )
169 beginRemoveRows( parent, row, row + count - 1 );
173 QgsDebugMsgLevel( QStringLiteral(
"remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 );
177 for (
int i = row; i < row + count; i++ )
179 for ( SortCache &cache : mSortCaches )
180 cache.sortCache.remove( mRowIdMap[i] );
181 mIdRowMap.remove( mRowIdMap[i] );
182 mRowIdMap.remove( i );
186 int n = mRowIdMap.size() + count;
187 for (
int i = row + count; i < n; i++ )
190 mIdRowMap[id] -= count;
191 mRowIdMap[i - count] = id;
192 mRowIdMap.remove( i );
198 QgsDebugMsgLevel( QStringLiteral(
"after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );
200 for ( QHash<QgsFeatureId, int>::const_iterator it = mIdRowMap.constBegin(); it != mIdRowMap.constEnd(); ++it )
204 for ( QHash<int, QgsFeatureId>::const_iterator it = mRowIdMap.constBegin(); it != mRowIdMap.constEnd(); ++it )
209 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
216 void QgsAttributeTableModel::featureAdded(
QgsFeatureId fid,
bool resettingModel )
221 if ( mFeat.
id() != fid )
222 featOk = loadFeatureAtId( fid );
226 for ( SortCache &cache : mSortCaches )
228 if ( cache.sortFieldIndex >= 0 )
231 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
232 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
233 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, mFeat.
attribute( cache.sortFieldIndex ) );
234 cache.sortCache.insert( mFeat.
id(), sortValue );
236 else if ( cache.sortCacheExpression.isValid() )
239 cache.sortCache[mFeat.
id()] = cache.sortCacheExpression.evaluate( &mExpressionContext );
244 if ( ! mIdRowMap.contains( fid ) )
246 int n = mRowIdMap.size();
247 if ( !resettingModel )
248 beginInsertRows( QModelIndex(), n, n );
249 mIdRowMap.insert( fid, n );
250 mRowIdMap.insert( n, fid );
251 if ( !resettingModel )
258 void QgsAttributeTableModel::updatedFields()
264 void QgsAttributeTableModel::editCommandEnded()
268 bulkEditCommandEnded( );
271 void QgsAttributeTableModel::attributeDeleted(
int idx )
274 for (
const SortCache &cache : mSortCaches )
276 if ( cache.sortCacheAttributes.contains( idx ) )
284 void QgsAttributeTableModel::layerDeleted()
286 mLayerCache =
nullptr;
289 mAttributeWidgetCaches.clear();
291 mWidgetFactories.clear();
292 mWidgetConfigs.clear();
293 mFieldFormatters.clear();
296 void QgsAttributeTableModel::fieldFormatterRemoved(
QgsFieldFormatter *fieldFormatter )
298 for (
int i = 0; i < mFieldFormatters.size(); ++i )
300 if ( mFieldFormatters.at( i ) == fieldFormatter )
305 void QgsAttributeTableModel::attributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
308 if ( mBulkEditCommandRunning )
310 mAttributeValueChanges.insert( QPair<QgsFeatureId, int>( fid, idx ), value );
313 QgsDebugMsgLevel( QStringLiteral(
"(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.
filterType() ), 2 );
315 for ( SortCache &cache : mSortCaches )
317 if ( cache.sortCacheAttributes.contains( idx ) )
319 if ( cache.sortFieldIndex == -1 )
321 if ( loadFeatureAtId( fid ) )
324 cache.sortCache[fid] = cache.sortCacheExpression.evaluate( &mExpressionContext );
330 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
331 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
332 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, value );
333 cache.sortCache.insert( fid, sortValue );
340 if ( loadFeatureAtId( fid ) )
345 if ( loadFeatureAtId( fid ) )
349 if ( !mIdRowMap.contains( fid ) )
362 if ( mIdRowMap.contains( fid ) )
373 void QgsAttributeTableModel::loadAttributes()
380 bool ins =
false, rm =
false;
385 mWidgetFactories.clear();
386 mAttributeWidgetCaches.clear();
387 mWidgetConfigs.clear();
389 for (
int idx = 0; idx < fields.
count(); ++idx )
395 mWidgetFactories.append( widgetFactory );
396 mWidgetConfigs.append( setup.
config() );
398 mFieldFormatters.append( fieldFormatter );
403 if ( mFieldCount + mExtraColumns < attributes.size() + mExtraColumns )
406 beginInsertColumns( QModelIndex(), mFieldCount + mExtraColumns, attributes.size() - 1 );
408 else if ( attributes.size() + mExtraColumns < mFieldCount + mExtraColumns )
411 beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount + mExtraColumns - 1 );
414 mFieldCount = attributes.size();
415 mAttributes = attributes;
417 for ( SortCache &cache : mSortCaches )
419 if ( cache.sortFieldIndex >= mAttributes.count() )
420 cache.sortFieldIndex = -1;
462 if ( t.elapsed() > 1000 )
471 featureAdded( mFeat.
id(), true );
484 if ( fieldName.isNull() )
486 mRowStylesMap.clear();
492 if ( fieldIndex == -1 )
497 emit dataChanged( index( 0, col ), index(
rowCount() - 1, col ) );
510 mRowIdMap.remove( rowA );
511 mRowIdMap.remove( rowB );
512 mRowIdMap.insert( rowA, b );
513 mRowIdMap.insert( rowB, a );
515 mIdRowMap.remove( a );
516 mIdRowMap.remove( b );
517 mIdRowMap.insert( a, rowB );
518 mIdRowMap.insert( b, rowA );
519 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
527 if ( !mIdRowMap.contains(
id ) )
529 QgsDebugMsg( QStringLiteral(
"idToRow: id %1 not in the map" ).arg(
id ) );
533 return mIdRowMap[id];
538 return index(
idToRow(
id ), 0 );
543 QModelIndexList indexes;
547 indexes.reserve( columns );
548 for (
int column = 0; column < columns; ++column )
550 indexes.append( index( row, column ) );
558 if ( !mRowIdMap.contains( row ) )
560 QgsDebugMsg( QStringLiteral(
"rowToId: row %1 not in the map" ).arg( row ) );
562 return std::numeric_limits<int>::min();
565 return mRowIdMap[row];
570 return mAttributes[col];
575 return mAttributes.indexOf( idx );
581 return mRowIdMap.size();
587 return std::max( 1, mFieldCount + mExtraColumns );
595 if ( role == Qt::DisplayRole )
597 if ( orientation == Qt::Vertical )
599 return QVariant( section );
601 else if ( section >= 0 && section < mFieldCount )
603 QString attributeName =
layer()->
fields().
at( mAttributes.at( section ) ).displayName();
604 return QVariant( attributeName );
608 return tr(
"extra column" );
611 else if ( role == Qt::ToolTipRole )
613 if ( orientation == Qt::Vertical )
616 return tr(
"Feature ID: %1" ).arg(
rowToId( section ) );
632 if ( !index.isValid() || !
layer() ||
633 ( role != Qt::TextAlignmentRole
634 && role != Qt::DisplayRole
635 && role != Qt::ToolTipRole
636 && role != Qt::EditRole
639 && role != Qt::BackgroundColorRole
640 && role != Qt::TextColorRole
641 && role != Qt::DecorationRole
642 && role != Qt::FontRole
653 if ( index.column() >= mFieldCount )
656 int fieldId = mAttributes.at( index.column() );
663 unsigned long cacheIndex = role -
SortRole;
664 if ( cacheIndex < mSortCaches.size() )
665 return mSortCaches.at( cacheIndex ).sortCache.value( rowId );
672 if ( role == Qt::TextAlignmentRole )
674 return QVariant( mFieldFormatters.at( index.column() )->alignmentFlag(
layer(), fieldId, mWidgetConfigs.at( index.column() ) ) | Qt::AlignVCenter );
677 if ( mFeat.
id() != rowId || !mFeat.
isValid() )
679 if ( !loadFeatureAtId( rowId ) )
680 return QVariant(
"ERROR" );
682 if ( mFeat.
id() != rowId )
683 return QVariant(
"ERROR" );
686 QVariant val = mFeat.
attribute( fieldId );
690 case Qt::DisplayRole:
691 case Qt::ToolTipRole:
692 return mFieldFormatters.at( index.column() )->representValue(
layer(),
694 mWidgetConfigs.at( index.column() ),
695 mAttributeWidgetCaches.at( index.column() ),
701 case Qt::BackgroundRole:
702 case Qt::TextColorRole:
703 case Qt::DecorationRole:
707 QList<QgsConditionalStyle> styles;
708 if ( mRowStylesMap.contains( index.row() ) )
710 styles = mRowStylesMap[index.row()];
715 mRowStylesMap.insert( index.row(), styles );
721 styles.insert( 0, rowstyle );
730 if ( role == Qt::DecorationRole )
732 if ( role == Qt::FontRole )
747 if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !
layer()->
isEditable() )
753 mRowStylesMap.remove( index.row() );
760 if ( !index.isValid() )
761 return Qt::ItemIsEnabled;
763 if ( index.column() >= mFieldCount || !
layer() )
764 return Qt::NoItemFlags;
766 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
768 const int fieldIndex = mAttributes[index.column()];
772 flags |= Qt::ItemIsEditable;
777 void QgsAttributeTableModel::bulkEditCommandStarted()
779 mBulkEditCommandRunning =
true;
780 mAttributeValueChanges.clear();
783 void QgsAttributeTableModel::bulkEditCommandEnded()
785 mBulkEditCommandRunning =
false;
788 int changeCount( mAttributeValueChanges.count() );
789 bool fullModelUpdate = changeCount > mLayerCache->
cacheSize() ||
792 QgsDebugMsgLevel( QStringLiteral(
"Bulk edit command ended with %1 modified rows over (%4), cache size is %2, starting %3 update." )
795 .arg( fullModelUpdate ? QStringLiteral(
"full" ) : QStringLiteral(
"incremental" ) )
799 if ( fullModelUpdate )
811 const auto keys = mAttributeValueChanges.keys();
812 for (
const auto &key : keys )
814 attributeValueChanged( key.first, key.second, mAttributeValueChanges.value( key ) );
815 int row(
idToRow( key.first ) );
817 minRow = std::min<int>( row, minRow );
818 minCol = std::min<int>( col, minCol );
819 maxRow = std::max<int>( row, maxRow );
820 maxCol = std::max<int>( col, maxCol );
822 emit dataChanged( createIndex( minRow, minCol ), createIndex( maxRow, maxCol ) );
824 mAttributeValueChanges.clear();
829 mFeat.
setId( std::numeric_limits<int>::min() );
830 emit dataChanged( index1, index2 );
851 for (
int i = 0; i < mAttributes.size(); i++ )
853 f.
setAttribute( mAttributes[i],
data( index( idx.row(), i ), Qt::EditRole ) );
861 if ( column == -1 || column >= mAttributes.count() )
873 if ( cacheIndex >= mSortCaches.size() )
875 mSortCaches.resize( cacheIndex + 1 );
877 SortCache &cache = mSortCaches[cacheIndex];
878 cache.sortCache.clear();
879 cache.sortCacheAttributes.clear();
880 cache.sortFieldIndex = -1;
881 if ( !expressionString.isEmpty() )
882 cache.sortCacheExpression =
QgsExpression( expressionString );
891 QVariant widgetCache;
892 QVariantMap widgetConfig;
894 if ( cache.sortCacheExpression.isField() )
900 if ( cache.sortFieldIndex == -1 )
902 cache.sortCacheExpression.prepare( &mExpressionContext );
904 const QSet<QString> &referencedColumns = cache.sortCacheExpression.referencedColumns();
906 for (
const QString &col : referencedColumns )
913 cache.sortCacheAttributes.append( cache.sortFieldIndex );
915 widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
916 widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
917 fieldFormatter = mFieldFormatters.at( cache.sortFieldIndex );
928 if ( cache.sortFieldIndex == -1 )
931 const QVariant cacheValue = cache.sortCacheExpression.evaluate( &mExpressionContext );
932 cache.sortCache.insert( f.
id(), cacheValue );
936 QVariant sortValue = fieldFormatter->
sortValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, f.
attribute( cache.sortFieldIndex ) );
937 cache.sortCache.insert( f.
id(), sortValue );
944 QString expressionString;
946 if ( cacheIndex >= mSortCaches.size() )
947 return expressionString;
949 const QgsExpression &expression = mSortCaches[cacheIndex].sortCacheExpression;
954 expressionString = QString();
956 return expressionString;
968 return mFeatureRequest;
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
bool isValid() const
Returns the validity of this feature.
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsActionManager * actions()
Returns all layer actions defined on this layer.
Wrapper for iterator of features from vector data provider or vector layer.
void featuresDeleted(const QgsFeatureIds &fids)
Emitted when features have been deleted.
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
int extraColumns() const
Empty extra columns to announce from this model.
bool acceptFeature(const QgsFeature &feature)
Check if a feature is accepted by this requests filter.
void doAction(QUuid actionId, const QgsFeature &feature, int defaultValueIndex=0, const QgsExpressionContextScope &scope=QgsExpressionContextScope())
Does the given action.
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
QSet< QgsFeatureId > QgsFeatureIds
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
const Flags & flags() const
Get the field index of this column.
void beforeRollBack()
Emitted before changes are rolled back.
void invalidated()
The cache has been invalidated and cleared.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QString sortCacheExpression(unsigned long cacheIndex=0) const
The expression which was used to fill the sorting cache at index cacheIndex.
void prefetchSortData(const QString &expression, unsigned long cacheIndex=0)
Prefetches the entire data for an expression.
static QString fieldToolTip(const QgsField &field)
Returns a HTML formatted tooltip string for a field, containing details like the field name...
void reload(const QModelIndex &index1, const QModelIndex &index2)
Reloads the model data between indices.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
FilterType filterType() const
Returns the filter type which is currently set on this request.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Container of fields for a vector layer.
bool setAttribute(int field, const QVariant &attr)
Set an attribute's value by field index.
bool validBackgroundColor() const
Check if the background color is valid for render.
QPixmap icon() const
The icon set for style generated from the set symbol.
void fieldConditionalStyleChanged(const QString &fieldName)
Handles updating the model when the conditional style for a field changes.
QgsVectorLayer * layer()
Returns the layer to which this cache belongs.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
void attributeValueChanged(QgsFeatureId fid, int field, const QVariant &value)
Emitted when an attribute is changed.
int count() const
Returns number of items.
void editCommandEnded()
Signal emitted, when an edit command successfully ended.
void resetModel()
Resets the model.
QModelIndex idToIndex(QgsFeatureId id) const
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
QVariant data(const QModelIndex &index, int role) const override
Returns data on the given index.
Get the feature id of the feature in this row.
QgsFeature feature(const QModelIndex &idx) const
Returns the feature attributes at given model index.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer and this cache.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
Role used for sorting start here.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Returns header data.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Conditional styling for a rule.
#define QgsDebugMsgLevel(str, level)
void setExtraColumns(int extraColumns)
Empty extra columns to announce from this model.
bool isValid() const
Checks if this expression is valid.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of columns.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories...
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
void afterRollBack()
Emitted after changes are rolled back.
bool isValid() const
isValid Check if this rule is valid.
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
An expression node which takes it value from a feature's field.
QColor backgroundColor() const
The background color for style.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
Remove rows.
static QgsConditionalStyle compressStyles(const QList< QgsConditionalStyle > &styles)
Compress a list of styles into a single style.
const QgsFeatureRequest & request() const
Gets the the feature request.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Encapsulate a field in an attribute table or data source.
void setId(QgsFeatureId id)
Sets the feature ID for this feature.
void cachedLayerDeleted()
Is emitted when the cached layer is deleted.
QModelIndexList idToIndexList(QgsFeatureId id) const
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName) const
Returns the conditional styles set for the field with matching fieldName.
QString expression() const
Returns the original, unmodified expression string.
This class caches features of a given QgsVectorLayer.
static int debugLevel()
Reads the environment variable QGIS_DEBUG and converts it to int.
void progress(int i, bool &cancel)
void modelChanged()
Model has been changed.
QColor textColor() const
The text color set for style.
QgsAttributeTableModel(QgsVectorLayerCache *layerCache, QObject *parent=nullptr)
Constructor.
int fieldCol(int idx) const
Gets column from field index.
void editCommandStarted(const QString &text)
Signal emitted when a new edit command has been started.
int fieldIdx(int col) const
Gets field index from column.
#define FID_TO_STRING(fid)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
bool featureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id.
bool validTextColor() const
Check if the text color is valid for render.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
void executeMapLayerAction(QgsMapLayerAction *action, const QModelIndex &idx) const
Execute a QgsMapLayerAction.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
void dataChanged()
Data of layer changed.
int cacheSize()
Returns the maximum number of features this cache will hold.
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
QList< int > QgsAttributeList
QFont font() const
The font for the style.
void swapRows(QgsFeatureId a, QgsFeatureId b)
Swaps two rows.
bool nextFeature(QgsFeature &f)
void attributeDeleted(int idx)
Will be emitted, when an attribute has been deleted from this vector layer.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
int idToRow(QgsFeatureId id) const
Maps feature id to table row.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Updates data on given index.
void triggerForFeature(QgsMapLayer *layer, const QgsFeature *feature)
Triggers the action with the specified layer and feature.
void executeAction(QUuid action, const QModelIndex &idx) const
Execute an action.
static bool fieldIsEditable(const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature)
An action which can run on map layers.
void prefetchColumnData(int column)
Caches the entire data for one column.
Qt::ItemFlags flags(const QModelIndex &index) const override
Returns item flags for the index.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.