48 : QAbstractTableModel( parent )
49 , mLayerCache( layerCache )
58 mFeat.
setId( std::numeric_limits<int>::min() );
60 if ( !
layer()->isSpatial() )
74 bool QgsAttributeTableModel::loadFeatureAtId(
QgsFeatureId fid )
const 78 if ( fid == std::numeric_limits<int>::min() )
97 void QgsAttributeTableModel::featuresDeleted(
const QgsFeatureIds &fids )
103 QgsDebugMsgLevel( QString(
"(%2) fid: %1, size: %3" ).arg( fid ).arg( mFeatureRequest.
filterType() ).arg( mIdRowMap.size() ), 4 );
110 std::sort( rows.begin(), rows.end() );
114 int currentRowCount = 0;
118 Q_FOREACH (
int row, rows )
121 qDebug() <<
"Row: " << row <<
", begin " << beginRow <<
", last " << lastRow <<
", current " << currentRowCount <<
", removed " << removedRows;
128 if ( row != lastRow + 1 && lastRow != -1 )
130 if ( rows.count() > 100 && currentRowCount < 10 )
135 removeRows( beginRow - removedRows, currentRowCount );
138 removedRows += currentRowCount;
148 removeRows( beginRow - removedRows, currentRowCount );
156 if ( row < 0 || count < 1 )
159 beginRemoveRows( parent, row, row + count - 1 );
163 QgsDebugMsgLevel( QString(
"remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 );
167 for (
int i = row; i < row + count; i++ )
169 for ( SortCache &cache : mSortCaches )
170 cache.sortCache.remove( mRowIdMap[i] );
171 mIdRowMap.remove( mRowIdMap[i] );
172 mRowIdMap.remove( i );
176 int n = mRowIdMap.size() + count;
177 for (
int i = row + count; i < n; i++ )
180 mIdRowMap[id] -= count;
181 mRowIdMap[i - count] = id;
182 mRowIdMap.remove( i );
188 QgsDebugMsgLevel( QString(
"after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );
190 for ( QHash<QgsFeatureId, int>::const_iterator it = mIdRowMap.constBegin(); it != mIdRowMap.constEnd(); ++it )
194 for ( QHash<int, QgsFeatureId>::const_iterator it = mRowIdMap.constBegin(); it != mRowIdMap.constEnd(); ++it )
199 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
206 void QgsAttributeTableModel::featureAdded(
QgsFeatureId fid,
bool resettingModel )
211 if ( mFeat.
id() != fid )
212 featOk = loadFeatureAtId( fid );
216 for ( SortCache &cache : mSortCaches )
218 if ( cache.sortFieldIndex >= 0 )
221 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
222 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
223 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, mFeat.
attribute( cache.sortFieldIndex ) );
224 cache.sortCache.insert( mFeat.
id(), sortValue );
226 else if ( cache.sortCacheExpression.isValid() )
229 cache.sortCache[mFeat.
id()] = cache.sortCacheExpression.evaluate( &mExpressionContext );
234 if ( ! mIdRowMap.contains( fid ) )
236 int n = mRowIdMap.size();
237 if ( !resettingModel )
238 beginInsertRows( QModelIndex(), n, n );
239 mIdRowMap.insert( fid, n );
240 mRowIdMap.insert( n, fid );
241 if ( !resettingModel )
248 void QgsAttributeTableModel::updatedFields()
254 void QgsAttributeTableModel::editCommandEnded()
258 mChangedCellBounds = QRect();
261 void QgsAttributeTableModel::attributeDeleted(
int idx )
264 for (
const SortCache &cache : mSortCaches )
266 if ( cache.sortCacheAttributes.contains( idx ) )
274 void QgsAttributeTableModel::layerDeleted()
276 mLayerCache =
nullptr;
279 mAttributeWidgetCaches.clear();
281 mWidgetFactories.clear();
282 mWidgetConfigs.clear();
283 mFieldFormatters.clear();
286 void QgsAttributeTableModel::fieldFormatterRemoved(
QgsFieldFormatter *fieldFormatter )
288 for (
int i = 0; i < mFieldFormatters.size(); ++i )
290 if ( mFieldFormatters.at( i ) == fieldFormatter )
295 void QgsAttributeTableModel::attributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
297 QgsDebugMsgLevel( QString(
"(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.
filterType() ), 3 );
299 for ( SortCache &cache : mSortCaches )
301 if ( cache.sortCacheAttributes.contains( idx ) )
303 if ( cache.sortFieldIndex == -1 )
305 if ( loadFeatureAtId( fid ) )
308 cache.sortCache[fid] = cache.sortCacheExpression.evaluate( &mExpressionContext );
314 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
315 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
316 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, value );
317 cache.sortCache.insert( fid, sortValue );
324 if ( loadFeatureAtId( fid ) )
329 if ( loadFeatureAtId( fid ) )
333 if ( !mIdRowMap.contains( fid ) )
346 if ( mIdRowMap.contains( fid ) )
357 void QgsAttributeTableModel::loadAttributes()
364 bool ins =
false, rm =
false;
369 mWidgetFactories.clear();
370 mAttributeWidgetCaches.clear();
371 mWidgetConfigs.clear();
373 for (
int idx = 0; idx < fields.
count(); ++idx )
379 mWidgetFactories.append( widgetFactory );
380 mWidgetConfigs.append( setup.
config() );
382 mFieldFormatters.append( fieldFormatter );
387 if ( mFieldCount + mExtraColumns < attributes.size() + mExtraColumns )
390 beginInsertColumns( QModelIndex(), mFieldCount + mExtraColumns, attributes.size() - 1 );
392 else if ( attributes.size() + mExtraColumns < mFieldCount + mExtraColumns )
395 beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount + mExtraColumns - 1 );
398 mFieldCount = attributes.size();
399 mAttributes = attributes;
401 for ( SortCache &cache : mSortCaches )
403 if ( cache.sortFieldIndex >= mAttributes.count() )
404 cache.sortFieldIndex = -1;
443 if ( t.elapsed() > 1000 )
452 featureAdded( mFeat.
id(), true );
464 if ( fieldName.isNull() )
466 mRowStylesMap.clear();
472 if ( fieldIndex == -1 )
477 emit dataChanged( index( 0, col ), index(
rowCount() - 1, col ) );
490 mRowIdMap.remove( rowA );
491 mRowIdMap.remove( rowB );
492 mRowIdMap.insert( rowA, b );
493 mRowIdMap.insert( rowB, a );
495 mIdRowMap.remove( a );
496 mIdRowMap.remove( b );
497 mIdRowMap.insert( a, rowB );
498 mIdRowMap.insert( b, rowA );
499 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
507 if ( !mIdRowMap.contains(
id ) )
509 QgsDebugMsg( QString(
"idToRow: id %1 not in the map" ).arg(
id ) );
513 return mIdRowMap[id];
518 return index(
idToRow(
id ), 0 );
523 QModelIndexList indexes;
527 indexes.reserve( columns );
528 for (
int column = 0; column < columns; ++column )
530 indexes.append( index( row, column ) );
538 if ( !mRowIdMap.contains( row ) )
540 QgsDebugMsg( QString(
"rowToId: row %1 not in the map" ).arg( row ) );
542 return std::numeric_limits<int>::min();
545 return mRowIdMap[row];
550 return mAttributes[col];
555 return mAttributes.indexOf( idx );
561 return mRowIdMap.size();
567 return std::max( 1, mFieldCount + mExtraColumns );
575 if ( role == Qt::DisplayRole )
577 if ( orientation == Qt::Vertical )
579 return QVariant( section );
581 else if ( section >= 0 && section < mFieldCount )
583 QString attributeName =
layer()->
fields().
at( mAttributes.at( section ) ).displayName();
584 return QVariant( attributeName );
588 return tr(
"extra column" );
591 else if ( role == Qt::ToolTipRole )
593 if ( orientation == Qt::Vertical )
596 return tr(
"Feature ID: %1" ).arg(
rowToId( section ) );
612 if ( !index.isValid() || !
layer() ||
613 ( role != Qt::TextAlignmentRole
614 && role != Qt::DisplayRole
615 && role != Qt::ToolTipRole
616 && role != Qt::EditRole
619 && role != Qt::BackgroundColorRole
620 && role != Qt::TextColorRole
621 && role != Qt::DecorationRole
622 && role != Qt::FontRole
633 if ( index.column() >= mFieldCount )
636 int fieldId = mAttributes.at( index.column() );
643 unsigned long cacheIndex = role -
SortRole;
644 if ( cacheIndex < mSortCaches.size() )
645 return mSortCaches.at( cacheIndex ).sortCache.value( rowId );
652 if ( role == Qt::TextAlignmentRole )
654 return QVariant( mFieldFormatters.at( index.column() )->alignmentFlag(
layer(), fieldId, mWidgetConfigs.at( index.column() ) ) | Qt::AlignVCenter );
657 if ( mFeat.
id() != rowId || !mFeat.
isValid() )
659 if ( !loadFeatureAtId( rowId ) )
660 return QVariant(
"ERROR" );
662 if ( mFeat.
id() != rowId )
663 return QVariant(
"ERROR" );
666 QVariant val = mFeat.
attribute( fieldId );
670 case Qt::DisplayRole:
671 case Qt::ToolTipRole:
672 return mFieldFormatters.at( index.column() )->representValue(
layer(), fieldId, mWidgetConfigs.at( index.column() ),
673 mAttributeWidgetCaches.at( index.column() ), val );
678 case Qt::BackgroundColorRole:
679 case Qt::TextColorRole:
680 case Qt::DecorationRole:
684 QList<QgsConditionalStyle> styles;
685 if ( mRowStylesMap.contains( index.row() ) )
687 styles = mRowStylesMap[index.row()];
692 mRowStylesMap.insert( index.row(), styles );
698 styles.insert( 0, rowstyle );
707 if ( role == Qt::DecorationRole )
709 if ( role == Qt::FontRole )
724 if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !
layer()->
isEditable() )
730 if ( mChangedCellBounds.isNull() )
732 mChangedCellBounds = QRect( index.column(), index.row(), 1, 1 );
736 if ( index.column() < mChangedCellBounds.left() )
738 mChangedCellBounds.setLeft( index.column() );
740 if ( index.row() < mChangedCellBounds.top() )
742 mChangedCellBounds.setTop( index.row() );
744 if ( index.column() > mChangedCellBounds.right() )
746 mChangedCellBounds.setRight( index.column() );
748 if ( index.row() > mChangedCellBounds.bottom() )
750 mChangedCellBounds.setBottom( index.row() );
759 if ( !index.isValid() )
760 return Qt::ItemIsEnabled;
762 if ( index.column() >= mFieldCount || !
layer() )
763 return Qt::NoItemFlags;
765 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
767 bool editable =
false;
768 const int fieldIndex = mAttributes[index.column()];
776 editable = fieldIsEditable( *info->
joinLayer(), srcFieldIndex, fid );
779 editable = fieldIsEditable( *
layer(), fieldIndex, fid );
782 flags |= Qt::ItemIsEditable;
796 mFeat.
setId( std::numeric_limits<int>::min() );
797 emit dataChanged( index1, index2 );
818 for (
int i = 0; i < mAttributes.size(); i++ )
820 f.
setAttribute( mAttributes[i],
data( index( idx.row(), i ), Qt::EditRole ) );
828 if ( column == -1 || column >= mAttributes.count() )
840 if ( cacheIndex >= mSortCaches.size() )
842 mSortCaches.resize( cacheIndex + 1 );
844 SortCache &cache = mSortCaches[cacheIndex];
845 cache.sortCache.clear();
846 cache.sortCacheAttributes.clear();
847 cache.sortFieldIndex = -1;
848 if ( !expressionString.isEmpty() )
849 cache.sortCacheExpression =
QgsExpression( expressionString );
858 QVariant widgetCache;
859 QVariantMap widgetConfig;
861 if ( cache.sortCacheExpression.isField() )
867 if ( cache.sortFieldIndex == -1 )
869 cache.sortCacheExpression.prepare( &mExpressionContext );
871 const QSet<QString> &referencedColumns = cache.sortCacheExpression.referencedColumns();
873 for (
const QString &col : referencedColumns )
880 cache.sortCacheAttributes.append( cache.sortFieldIndex );
882 widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
883 widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
884 fieldFormatter = mFieldFormatters.at( cache.sortFieldIndex );
895 if ( cache.sortFieldIndex == -1 )
898 const QVariant cacheValue = cache.sortCacheExpression.evaluate( &mExpressionContext );
899 cache.sortCache.insert( f.
id(), cacheValue );
903 QVariant sortValue = fieldFormatter->
sortValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, f.
attribute( cache.sortFieldIndex ) );
904 cache.sortCache.insert( f.
id(), sortValue );
911 QString expressionString;
913 if ( cacheIndex >= mSortCaches.size() )
914 return expressionString;
916 const QgsExpression &expression = mSortCaches[cacheIndex].sortCacheExpression;
921 expressionString = QString();
923 return expressionString;
935 return mFeatureRequest;
int lookupField(const QString &fieldName) const
Look 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...
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field's origin (value from an enumeration)
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
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 invalidated()
The cache has been invalidated and cleared.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QSet< QgsFeatureId > QgsFeatureIds
QString sortCacheExpression(unsigned long cacheIndex=0) const
The expression which was used to fill the sorting cache at index cacheIndex.
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.
#define FID_TO_STRING(fid)
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)
Is emitted when an attribute is changed.
bool isEditable() const override
Returns true if the provider is in editing mode.
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)
Is emitted, when a new feature has been added to the layer and this cache.
Roles used for sorting start here.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Returns header data.
Conditional styling for a rule.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be null if the reference was set by layer ID and not resolved yet) ...
QgsFields fields() const override
Returns the list of fields of this layer.
#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.
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.
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.
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.
QgsEditFormConfig editFormConfig
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
QModelIndexList idToIndexList(QgsFeatureId id) const
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.
int fieldIdx(int col) const
Gets field index from column.
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.
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
QgsVectorDataProvider * dataProvider() override
Returns the layer's data provider.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
QList< int > QgsAttributeList
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer. ...
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.
Represents a vector layer which manages a vector based data sets.
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()
Is 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.
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.