48 : QAbstractTableModel( parent )
49 , mLayerCache( layerCache )
58 mFeat.
setId( std::numeric_limits<int>::min() );
60 if ( !
layer()->isSpatial() )
80 bool QgsAttributeTableModel::loadFeatureAtId(
QgsFeatureId fid )
const 84 if ( fid == std::numeric_limits<int>::min() )
103 void QgsAttributeTableModel::featuresDeleted(
const QgsFeatureIds &fids )
109 QgsDebugMsgLevel( QStringLiteral(
"(%2) fid: %1, size: %3" ).arg( fid ).arg( mFeatureRequest.
filterType() ).arg( mIdRowMap.size() ), 4 );
116 std::sort( rows.begin(), rows.end() );
120 int currentRowCount = 0;
124 Q_FOREACH (
int row, rows )
127 qDebug() <<
"Row: " << row <<
", begin " << beginRow <<
", last " << lastRow <<
", current " << currentRowCount <<
", removed " << removedRows;
134 if ( row != lastRow + 1 && lastRow != -1 )
136 if ( rows.count() > 100 && currentRowCount < 10 )
141 removeRows( beginRow - removedRows, currentRowCount );
144 removedRows += currentRowCount;
154 removeRows( beginRow - removedRows, currentRowCount );
162 if ( row < 0 || count < 1 )
165 beginRemoveRows( parent, row, row + count - 1 );
169 QgsDebugMsgLevel( QStringLiteral(
"remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 );
173 for (
int i = row; i < row + count; i++ )
175 for ( SortCache &cache : mSortCaches )
176 cache.sortCache.remove( mRowIdMap[i] );
177 mIdRowMap.remove( mRowIdMap[i] );
178 mRowIdMap.remove( i );
182 int n = mRowIdMap.size() + count;
183 for (
int i = row + count; i < n; i++ )
186 mIdRowMap[id] -= count;
187 mRowIdMap[i - count] = id;
188 mRowIdMap.remove( i );
194 QgsDebugMsgLevel( QStringLiteral(
"after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );
196 for ( QHash<QgsFeatureId, int>::const_iterator it = mIdRowMap.constBegin(); it != mIdRowMap.constEnd(); ++it )
200 for ( QHash<int, QgsFeatureId>::const_iterator it = mRowIdMap.constBegin(); it != mRowIdMap.constEnd(); ++it )
205 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
212 void QgsAttributeTableModel::featureAdded(
QgsFeatureId fid,
bool resettingModel )
217 if ( mFeat.
id() != fid )
218 featOk = loadFeatureAtId( fid );
222 for ( SortCache &cache : mSortCaches )
224 if ( cache.sortFieldIndex >= 0 )
227 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
228 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
229 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, mFeat.
attribute( cache.sortFieldIndex ) );
230 cache.sortCache.insert( mFeat.
id(), sortValue );
232 else if ( cache.sortCacheExpression.isValid() )
235 cache.sortCache[mFeat.
id()] = cache.sortCacheExpression.evaluate( &mExpressionContext );
240 if ( ! mIdRowMap.contains( fid ) )
242 int n = mRowIdMap.size();
243 if ( !resettingModel )
244 beginInsertRows( QModelIndex(), n, n );
245 mIdRowMap.insert( fid, n );
246 mRowIdMap.insert( n, fid );
247 if ( !resettingModel )
254 void QgsAttributeTableModel::updatedFields()
260 void QgsAttributeTableModel::editCommandEnded()
264 bulkEditCommandEnded( );
267 void QgsAttributeTableModel::attributeDeleted(
int idx )
270 for (
const SortCache &cache : mSortCaches )
272 if ( cache.sortCacheAttributes.contains( idx ) )
280 void QgsAttributeTableModel::layerDeleted()
282 mLayerCache =
nullptr;
285 mAttributeWidgetCaches.clear();
287 mWidgetFactories.clear();
288 mWidgetConfigs.clear();
289 mFieldFormatters.clear();
292 void QgsAttributeTableModel::fieldFormatterRemoved(
QgsFieldFormatter *fieldFormatter )
294 for (
int i = 0; i < mFieldFormatters.size(); ++i )
296 if ( mFieldFormatters.at( i ) == fieldFormatter )
301 void QgsAttributeTableModel::attributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
304 if ( mBulkEditCommandRunning )
306 mAttributeValueChanges.insert( QPair<QgsFeatureId, int>( fid, idx ), value );
309 QgsDebugMsgLevel( QStringLiteral(
"(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.
filterType() ), 2 );
311 for ( SortCache &cache : mSortCaches )
313 if ( cache.sortCacheAttributes.contains( idx ) )
315 if ( cache.sortFieldIndex == -1 )
317 if ( loadFeatureAtId( fid ) )
320 cache.sortCache[fid] = cache.sortCacheExpression.evaluate( &mExpressionContext );
326 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
327 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
328 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, value );
329 cache.sortCache.insert( fid, sortValue );
336 if ( loadFeatureAtId( fid ) )
341 if ( loadFeatureAtId( fid ) )
345 if ( !mIdRowMap.contains( fid ) )
358 if ( mIdRowMap.contains( fid ) )
369 void QgsAttributeTableModel::loadAttributes()
376 bool ins =
false, rm =
false;
381 mWidgetFactories.clear();
382 mAttributeWidgetCaches.clear();
383 mWidgetConfigs.clear();
385 for (
int idx = 0; idx < fields.
count(); ++idx )
391 mWidgetFactories.append( widgetFactory );
392 mWidgetConfigs.append( setup.
config() );
394 mFieldFormatters.append( fieldFormatter );
399 if ( mFieldCount + mExtraColumns < attributes.size() + mExtraColumns )
402 beginInsertColumns( QModelIndex(), mFieldCount + mExtraColumns, attributes.size() - 1 );
404 else if ( attributes.size() + mExtraColumns < mFieldCount + mExtraColumns )
407 beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount + mExtraColumns - 1 );
410 mFieldCount = attributes.size();
411 mAttributes = attributes;
413 for ( SortCache &cache : mSortCaches )
415 if ( cache.sortFieldIndex >= mAttributes.count() )
416 cache.sortFieldIndex = -1;
458 if ( t.elapsed() > 1000 )
467 featureAdded( mFeat.
id(), true );
480 if ( fieldName.isNull() )
482 mRowStylesMap.clear();
488 if ( fieldIndex == -1 )
493 emit dataChanged( index( 0, col ), index(
rowCount() - 1, col ) );
506 mRowIdMap.remove( rowA );
507 mRowIdMap.remove( rowB );
508 mRowIdMap.insert( rowA, b );
509 mRowIdMap.insert( rowB, a );
511 mIdRowMap.remove( a );
512 mIdRowMap.remove( b );
513 mIdRowMap.insert( a, rowB );
514 mIdRowMap.insert( b, rowA );
515 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
523 if ( !mIdRowMap.contains(
id ) )
525 QgsDebugMsg( QStringLiteral(
"idToRow: id %1 not in the map" ).arg(
id ) );
529 return mIdRowMap[id];
534 return index(
idToRow(
id ), 0 );
539 QModelIndexList indexes;
543 indexes.reserve( columns );
544 for (
int column = 0; column < columns; ++column )
546 indexes.append( index( row, column ) );
554 if ( !mRowIdMap.contains( row ) )
556 QgsDebugMsg( QStringLiteral(
"rowToId: row %1 not in the map" ).arg( row ) );
558 return std::numeric_limits<int>::min();
561 return mRowIdMap[row];
566 return mAttributes[col];
571 return mAttributes.indexOf( idx );
577 return mRowIdMap.size();
583 return std::max( 1, mFieldCount + mExtraColumns );
591 if ( role == Qt::DisplayRole )
593 if ( orientation == Qt::Vertical )
595 return QVariant( section );
597 else if ( section >= 0 && section < mFieldCount )
599 QString attributeName =
layer()->
fields().
at( mAttributes.at( section ) ).displayName();
600 return QVariant( attributeName );
604 return tr(
"extra column" );
607 else if ( role == Qt::ToolTipRole )
609 if ( orientation == Qt::Vertical )
612 return tr(
"Feature ID: %1" ).arg(
rowToId( section ) );
628 if ( !index.isValid() || !
layer() ||
629 ( role != Qt::TextAlignmentRole
630 && role != Qt::DisplayRole
631 && role != Qt::ToolTipRole
632 && role != Qt::EditRole
635 && role != Qt::BackgroundColorRole
636 && role != Qt::TextColorRole
637 && role != Qt::DecorationRole
638 && role != Qt::FontRole
649 if ( index.column() >= mFieldCount )
652 int fieldId = mAttributes.at( index.column() );
659 unsigned long cacheIndex = role -
SortRole;
660 if ( cacheIndex < mSortCaches.size() )
661 return mSortCaches.at( cacheIndex ).sortCache.value( rowId );
668 if ( role == Qt::TextAlignmentRole )
670 return QVariant( mFieldFormatters.at( index.column() )->alignmentFlag(
layer(), fieldId, mWidgetConfigs.at( index.column() ) ) | Qt::AlignVCenter );
673 if ( mFeat.
id() != rowId || !mFeat.
isValid() )
675 if ( !loadFeatureAtId( rowId ) )
676 return QVariant(
"ERROR" );
678 if ( mFeat.
id() != rowId )
679 return QVariant(
"ERROR" );
682 QVariant val = mFeat.
attribute( fieldId );
686 case Qt::DisplayRole:
687 case Qt::ToolTipRole:
688 return mFieldFormatters.at( index.column() )->representValue(
layer(), fieldId, mWidgetConfigs.at( index.column() ),
689 mAttributeWidgetCaches.at( index.column() ), val );
694 case Qt::BackgroundRole:
695 case Qt::TextColorRole:
696 case Qt::DecorationRole:
700 QList<QgsConditionalStyle> styles;
701 if ( mRowStylesMap.contains( index.row() ) )
703 styles = mRowStylesMap[index.row()];
708 mRowStylesMap.insert( index.row(), styles );
714 styles.insert( 0, rowstyle );
723 if ( role == Qt::DecorationRole )
725 if ( role == Qt::FontRole )
740 if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !
layer()->
isEditable() )
746 mRowStylesMap.remove( index.row() );
753 if ( !index.isValid() )
754 return Qt::ItemIsEnabled;
756 if ( index.column() >= mFieldCount || !
layer() )
757 return Qt::NoItemFlags;
759 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
761 bool editable =
false;
762 const int fieldIndex = mAttributes[index.column()];
770 editable = fieldIsEditable( *info->
joinLayer(), srcFieldIndex, fid );
773 editable = fieldIsEditable( *
layer(), fieldIndex, fid );
776 flags |= Qt::ItemIsEditable;
788 void QgsAttributeTableModel::bulkEditCommandStarted()
790 mBulkEditCommandRunning =
true;
791 mAttributeValueChanges.clear();
794 void QgsAttributeTableModel::bulkEditCommandEnded()
796 mBulkEditCommandRunning =
false;
799 int changeCount( mAttributeValueChanges.count() );
800 bool fullModelUpdate = changeCount > mLayerCache->
cacheSize() ||
803 QgsDebugMsgLevel( QStringLiteral(
"Bulk edit command ended with %1 modified rows over (%4), cache size is %2, starting %3 update." )
806 .arg( fullModelUpdate ? QStringLiteral(
"full" ) : QStringLiteral(
"incremental" ) )
810 if ( fullModelUpdate )
822 const auto keys = mAttributeValueChanges.keys();
823 for (
const auto &key : keys )
825 attributeValueChanged( key.first, key.second, mAttributeValueChanges.value( key ) );
826 int row(
idToRow( key.first ) );
828 minRow = std::min<int>( row, minRow );
829 minCol = std::min<int>( col, minCol );
830 maxRow = std::max<int>( row, maxRow );
831 maxCol = std::max<int>( col, maxCol );
833 emit dataChanged( createIndex( minRow, minCol ), createIndex( maxRow, maxCol ) );
835 mAttributeValueChanges.clear();
840 mFeat.
setId( std::numeric_limits<int>::min() );
841 emit dataChanged( index1, index2 );
862 for (
int i = 0; i < mAttributes.size(); i++ )
864 f.
setAttribute( mAttributes[i],
data( index( idx.row(), i ), Qt::EditRole ) );
872 if ( column == -1 || column >= mAttributes.count() )
884 if ( cacheIndex >= mSortCaches.size() )
886 mSortCaches.resize( cacheIndex + 1 );
888 SortCache &cache = mSortCaches[cacheIndex];
889 cache.sortCache.clear();
890 cache.sortCacheAttributes.clear();
891 cache.sortFieldIndex = -1;
892 if ( !expressionString.isEmpty() )
893 cache.sortCacheExpression =
QgsExpression( expressionString );
902 QVariant widgetCache;
903 QVariantMap widgetConfig;
905 if ( cache.sortCacheExpression.isField() )
911 if ( cache.sortFieldIndex == -1 )
913 cache.sortCacheExpression.prepare( &mExpressionContext );
915 const QSet<QString> &referencedColumns = cache.sortCacheExpression.referencedColumns();
917 for (
const QString &col : referencedColumns )
924 cache.sortCacheAttributes.append( cache.sortFieldIndex );
926 widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
927 widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
928 fieldFormatter = mFieldFormatters.at( cache.sortFieldIndex );
939 if ( cache.sortFieldIndex == -1 )
942 const QVariant cacheValue = cache.sortCacheExpression.evaluate( &mExpressionContext );
943 cache.sortCache.insert( f.
id(), cacheValue );
947 QVariant sortValue = fieldFormatter->
sortValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, f.
attribute( cache.sortFieldIndex ) );
948 cache.sortCache.insert( f.
id(), sortValue );
955 QString expressionString;
957 if ( cacheIndex >= mSortCaches.size() )
958 return expressionString;
960 const QgsExpression &expression = mSortCaches[cacheIndex].sortCacheExpression;
965 expressionString = QString();
967 return expressionString;
979 return mFeatureRequest;
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.
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.
const Flags & flags() const
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
QModelIndexList idToIndexList(QgsFeatureId id) const
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)
bool validTextColor() const
Check if the text color is valid for render.
Get the field index of this column.
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
bool isValid() const
Returns the validity of this feature.
void beforeRollBack()
Is emitted, before changes are rolled back.
void invalidated()
The cache has been invalidated and cleared.
QColor textColor() const
The text color set for style.
bool validBackgroundColor() const
Check if the background color is valid for render.
bool isValid() const
Checks if this expression is valid.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
int extraColumns() const
Empty extra columns to announce from this model.
QFont font() const
The font for the style.
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName)
Returns the conditional styles set for the field UI properties.
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.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
QModelIndex idToIndex(QgsFeatureId id) const
Container of fields for a vector layer.
bool setAttribute(int field, const QVariant &attr)
Set an attribute's value by field index.
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.
const QgsFeatureRequest & request() const
Gets the the feature request.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
void attributeValueChanged(QgsFeatureId fid, int field, const QVariant &value)
Is emitted when an attribute is changed.
void editCommandEnded()
Signal emitted, when an edit command successfully ended.
void resetModel()
Resets the model.
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.
void featureAdded(QgsFeatureId fid)
Is emitted, when a new feature has been added to the layer and this cache.
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer. ...
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
Roles used for sorting start here.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Returns header data.
QPixmap icon() const
The icon set for style generated from the set symbol.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Conditional styling for a rule.
void executeMapLayerAction(QgsMapLayerAction *action, const QModelIndex &idx) const
Execute a QgsMapLayerAction.
#define QgsDebugMsgLevel(str, level)
void setExtraColumns(int extraColumns)
Empty extra columns to announce from this model.
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()
Is emitted, after changes are rolled back.
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
Defines left outer join from our vector layer to some other vector layer.
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.
int count() const
Returns number of items.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
FilterType filterType() const
Returns the filter type which is currently set on this request.
static QgsConditionalStyle compressStyles(const QList< QgsConditionalStyle > &styles)
Compress a list of styles into a single style.
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.
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
void cachedLayerDeleted()
Is emitted when the cached layer is deleted.
QgsEditFormConfig editFormConfig
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
QgsFeature feature(const QModelIndex &idx) const
Returns the feature attributes at given model index.
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.
QgsAttributeTableModel(QgsVectorLayerCache *layerCache, QObject *parent=nullptr)
Constructor.
void executeAction(QUuid action, const QModelIndex &idx) const
Execute an action.
void editCommandStarted(const QString &text)
Signal emitted when a new edit command has been started.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
#define FID_TO_STRING(fid)
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
int fieldCol(int idx) const
Gets column from field index.
bool featureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id.
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.
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field's origin (value from an enumeration)
int idToRow(QgsFeatureId id) const
Maps feature id to table row.
void dataChanged()
Data of layer changed.
QString expression() const
Returns the original, unmodified expression string.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be null if the reference was set by layer ID and not resolved yet) ...
int cacheSize()
Returns the maximum number of features this cache will hold.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
int fieldIdx(int col) const
Gets field index from column.
bool isValid() const
isValid Check if this rule is valid.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider.
QList< int > QgsAttributeList
void swapRows(QgsFeatureId a, QgsFeatureId b)
Swaps two rows.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
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.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
void updatedFields()
Is emitted, whenever the fields available from this layer have been changed.
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.
Allows modification of attribute values.
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.