49 : QAbstractTableModel( parent )
50 , mLayerCache( layerCache )
59 mFeat.
setId( std::numeric_limits<int>::min() );
61 if ( !
layer()->isSpatial() )
81 bool QgsAttributeTableModel::loadFeatureAtId(
QgsFeatureId fid )
const 85 if ( fid == std::numeric_limits<int>::min() )
104 void QgsAttributeTableModel::featuresDeleted(
const QgsFeatureIds &fids )
110 QgsDebugMsgLevel( QStringLiteral(
"(%2) fid: %1, size: %3" ).arg( fid ).arg( mFeatureRequest.
filterType() ).arg( mIdRowMap.size() ), 4 );
117 std::sort( rows.begin(), rows.end() );
121 int currentRowCount = 0;
125 Q_FOREACH (
int row, rows )
128 qDebug() <<
"Row: " << row <<
", begin " << beginRow <<
", last " << lastRow <<
", current " << currentRowCount <<
", removed " << removedRows;
135 if ( row != lastRow + 1 && lastRow != -1 )
137 if ( rows.count() > 100 && currentRowCount < 10 )
142 removeRows( beginRow - removedRows, currentRowCount );
145 removedRows += currentRowCount;
155 removeRows( beginRow - removedRows, currentRowCount );
163 if ( row < 0 || count < 1 )
166 beginRemoveRows( parent, row, row + count - 1 );
170 QgsDebugMsgLevel( QStringLiteral(
"remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 );
174 for (
int i = row; i < row + count; i++ )
176 for ( SortCache &cache : mSortCaches )
177 cache.sortCache.remove( mRowIdMap[i] );
178 mIdRowMap.remove( mRowIdMap[i] );
179 mRowIdMap.remove( i );
183 int n = mRowIdMap.size() + count;
184 for (
int i = row + count; i < n; i++ )
187 mIdRowMap[id] -= count;
188 mRowIdMap[i - count] = id;
189 mRowIdMap.remove( i );
195 QgsDebugMsgLevel( QStringLiteral(
"after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );
197 for ( QHash<QgsFeatureId, int>::const_iterator it = mIdRowMap.constBegin(); it != mIdRowMap.constEnd(); ++it )
201 for ( QHash<int, QgsFeatureId>::const_iterator it = mRowIdMap.constBegin(); it != mRowIdMap.constEnd(); ++it )
206 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
213 void QgsAttributeTableModel::featureAdded(
QgsFeatureId fid,
bool resettingModel )
218 if ( mFeat.
id() != fid )
219 featOk = loadFeatureAtId( fid );
223 for ( SortCache &cache : mSortCaches )
225 if ( cache.sortFieldIndex >= 0 )
228 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
229 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
230 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, mFeat.
attribute( cache.sortFieldIndex ) );
231 cache.sortCache.insert( mFeat.
id(), sortValue );
233 else if ( cache.sortCacheExpression.isValid() )
236 cache.sortCache[mFeat.
id()] = cache.sortCacheExpression.evaluate( &mExpressionContext );
241 if ( ! mIdRowMap.contains( fid ) )
243 int n = mRowIdMap.size();
244 if ( !resettingModel )
245 beginInsertRows( QModelIndex(), n, n );
246 mIdRowMap.insert( fid, n );
247 mRowIdMap.insert( n, fid );
248 if ( !resettingModel )
255 void QgsAttributeTableModel::updatedFields()
261 void QgsAttributeTableModel::editCommandEnded()
265 bulkEditCommandEnded( );
268 void QgsAttributeTableModel::attributeDeleted(
int idx )
271 for (
const SortCache &cache : mSortCaches )
273 if ( cache.sortCacheAttributes.contains( idx ) )
281 void QgsAttributeTableModel::layerDeleted()
283 mLayerCache =
nullptr;
286 mAttributeWidgetCaches.clear();
288 mWidgetFactories.clear();
289 mWidgetConfigs.clear();
290 mFieldFormatters.clear();
293 void QgsAttributeTableModel::fieldFormatterRemoved(
QgsFieldFormatter *fieldFormatter )
295 for (
int i = 0; i < mFieldFormatters.size(); ++i )
297 if ( mFieldFormatters.at( i ) == fieldFormatter )
302 void QgsAttributeTableModel::attributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
305 if ( mBulkEditCommandRunning )
307 mAttributeValueChanges.insert( QPair<QgsFeatureId, int>( fid, idx ), value );
310 QgsDebugMsgLevel( QStringLiteral(
"(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.
filterType() ), 2 );
312 for ( SortCache &cache : mSortCaches )
314 if ( cache.sortCacheAttributes.contains( idx ) )
316 if ( cache.sortFieldIndex == -1 )
318 if ( loadFeatureAtId( fid ) )
321 cache.sortCache[fid] = cache.sortCacheExpression.evaluate( &mExpressionContext );
327 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
328 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
329 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, value );
330 cache.sortCache.insert( fid, sortValue );
337 if ( loadFeatureAtId( fid ) )
342 if ( loadFeatureAtId( fid ) )
346 if ( !mIdRowMap.contains( fid ) )
359 if ( mIdRowMap.contains( fid ) )
370 void QgsAttributeTableModel::loadAttributes()
377 bool ins =
false, rm =
false;
382 mWidgetFactories.clear();
383 mAttributeWidgetCaches.clear();
384 mWidgetConfigs.clear();
386 for (
int idx = 0; idx < fields.
count(); ++idx )
392 mWidgetFactories.append( widgetFactory );
393 mWidgetConfigs.append( setup.
config() );
395 mFieldFormatters.append( fieldFormatter );
400 if ( mFieldCount + mExtraColumns < attributes.size() + mExtraColumns )
403 beginInsertColumns( QModelIndex(), mFieldCount + mExtraColumns, attributes.size() - 1 );
405 else if ( attributes.size() + mExtraColumns < mFieldCount + mExtraColumns )
408 beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount + mExtraColumns - 1 );
411 mFieldCount = attributes.size();
412 mAttributes = attributes;
414 for ( SortCache &cache : mSortCaches )
416 if ( cache.sortFieldIndex >= mAttributes.count() )
417 cache.sortFieldIndex = -1;
459 if ( t.elapsed() > 1000 )
468 featureAdded( mFeat.
id(), true );
481 if ( fieldName.isNull() )
483 mRowStylesMap.clear();
489 if ( fieldIndex == -1 )
494 emit dataChanged( index( 0, col ), index(
rowCount() - 1, col ) );
507 mRowIdMap.remove( rowA );
508 mRowIdMap.remove( rowB );
509 mRowIdMap.insert( rowA, b );
510 mRowIdMap.insert( rowB, a );
512 mIdRowMap.remove( a );
513 mIdRowMap.remove( b );
514 mIdRowMap.insert( a, rowB );
515 mIdRowMap.insert( b, rowA );
516 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
524 if ( !mIdRowMap.contains(
id ) )
526 QgsDebugMsg( QStringLiteral(
"idToRow: id %1 not in the map" ).arg(
id ) );
530 return mIdRowMap[id];
535 return index(
idToRow(
id ), 0 );
540 QModelIndexList indexes;
544 indexes.reserve( columns );
545 for (
int column = 0; column < columns; ++column )
547 indexes.append( index( row, column ) );
555 if ( !mRowIdMap.contains( row ) )
557 QgsDebugMsg( QStringLiteral(
"rowToId: row %1 not in the map" ).arg( row ) );
559 return std::numeric_limits<int>::min();
562 return mRowIdMap[row];
567 return mAttributes[col];
572 return mAttributes.indexOf( idx );
578 return mRowIdMap.size();
584 return std::max( 1, mFieldCount + mExtraColumns );
592 if ( role == Qt::DisplayRole )
594 if ( orientation == Qt::Vertical )
596 return QVariant( section );
598 else if ( section >= 0 && section < mFieldCount )
600 QString attributeName =
layer()->
fields().
at( mAttributes.at( section ) ).displayName();
601 return QVariant( attributeName );
605 return tr(
"extra column" );
608 else if ( role == Qt::ToolTipRole )
610 if ( orientation == Qt::Vertical )
613 return tr(
"Feature ID: %1" ).arg(
rowToId( section ) );
629 if ( !index.isValid() || !
layer() ||
630 ( role != Qt::TextAlignmentRole
631 && role != Qt::DisplayRole
632 && role != Qt::ToolTipRole
633 && role != Qt::EditRole
636 && role != Qt::BackgroundColorRole
637 && role != Qt::TextColorRole
638 && role != Qt::DecorationRole
639 && role != Qt::FontRole
650 if ( index.column() >= mFieldCount )
653 int fieldId = mAttributes.at( index.column() );
660 unsigned long cacheIndex = role -
SortRole;
661 if ( cacheIndex < mSortCaches.size() )
662 return mSortCaches.at( cacheIndex ).sortCache.value( rowId );
669 if ( role == Qt::TextAlignmentRole )
671 return QVariant( mFieldFormatters.at( index.column() )->alignmentFlag(
layer(), fieldId, mWidgetConfigs.at( index.column() ) ) | Qt::AlignVCenter );
674 if ( mFeat.
id() != rowId || !mFeat.
isValid() )
676 if ( !loadFeatureAtId( rowId ) )
677 return QVariant(
"ERROR" );
679 if ( mFeat.
id() != rowId )
680 return QVariant(
"ERROR" );
683 QVariant val = mFeat.
attribute( fieldId );
687 case Qt::DisplayRole:
688 case Qt::ToolTipRole:
689 return mFieldFormatters.at( index.column() )->representValue(
layer(), fieldId, mWidgetConfigs.at( index.column() ),
690 mAttributeWidgetCaches.at( index.column() ), val );
695 case Qt::BackgroundRole:
696 case Qt::TextColorRole:
697 case Qt::DecorationRole:
701 QList<QgsConditionalStyle> styles;
702 if ( mRowStylesMap.contains( index.row() ) )
704 styles = mRowStylesMap[index.row()];
709 mRowStylesMap.insert( index.row(), styles );
715 styles.insert( 0, rowstyle );
724 if ( role == Qt::DecorationRole )
726 if ( role == Qt::FontRole )
741 if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !
layer()->
isEditable() )
747 mRowStylesMap.remove( index.row() );
754 if ( !index.isValid() )
755 return Qt::ItemIsEnabled;
757 if ( index.column() >= mFieldCount || !
layer() )
758 return Qt::NoItemFlags;
760 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
762 bool editable =
false;
763 const int fieldIndex = mAttributes[index.column()];
771 editable = fieldIsEditable( *info->
joinLayer(), srcFieldIndex, fid );
774 editable = fieldIsEditable( *
layer(), fieldIndex, fid );
777 flags |= Qt::ItemIsEditable;
789 void QgsAttributeTableModel::bulkEditCommandStarted()
791 mBulkEditCommandRunning =
true;
792 mAttributeValueChanges.clear();
795 void QgsAttributeTableModel::bulkEditCommandEnded()
797 mBulkEditCommandRunning =
false;
800 int changeCount( mAttributeValueChanges.count() );
801 bool fullModelUpdate = changeCount > mLayerCache->
cacheSize() ||
804 QgsDebugMsgLevel( QStringLiteral(
"Bulk edit command ended with %1 modified rows over (%4), cache size is %2, starting %3 update." )
807 .arg( fullModelUpdate ? QStringLiteral(
"full" ) : QStringLiteral(
"incremental" ) )
811 if ( fullModelUpdate )
823 const auto keys = mAttributeValueChanges.keys();
824 for (
const auto &key : keys )
826 attributeValueChanged( key.first, key.second, mAttributeValueChanges.value( key ) );
827 int row(
idToRow( key.first ) );
829 minRow = std::min<int>( row, minRow );
830 minCol = std::min<int>( col, minCol );
831 maxRow = std::max<int>( row, maxRow );
832 maxCol = std::max<int>( col, maxCol );
834 emit dataChanged( createIndex( minRow, minCol ), createIndex( maxRow, maxCol ) );
836 mAttributeValueChanges.clear();
841 mFeat.
setId( std::numeric_limits<int>::min() );
842 emit dataChanged( index1, index2 );
863 for (
int i = 0; i < mAttributes.size(); i++ )
865 f.
setAttribute( mAttributes[i],
data( index( idx.row(), i ), Qt::EditRole ) );
873 if ( column == -1 || column >= mAttributes.count() )
885 if ( cacheIndex >= mSortCaches.size() )
887 mSortCaches.resize( cacheIndex + 1 );
889 SortCache &cache = mSortCaches[cacheIndex];
890 cache.sortCache.clear();
891 cache.sortCacheAttributes.clear();
892 cache.sortFieldIndex = -1;
893 if ( !expressionString.isEmpty() )
894 cache.sortCacheExpression =
QgsExpression( expressionString );
903 QVariant widgetCache;
904 QVariantMap widgetConfig;
906 if ( cache.sortCacheExpression.isField() )
912 if ( cache.sortFieldIndex == -1 )
914 cache.sortCacheExpression.prepare( &mExpressionContext );
916 const QSet<QString> &referencedColumns = cache.sortCacheExpression.referencedColumns();
918 for (
const QString &col : referencedColumns )
925 cache.sortCacheAttributes.append( cache.sortFieldIndex );
927 widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
928 widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
929 fieldFormatter = mFieldFormatters.at( cache.sortFieldIndex );
940 if ( cache.sortFieldIndex == -1 )
943 const QVariant cacheValue = cache.sortCacheExpression.evaluate( &mExpressionContext );
944 cache.sortCache.insert( f.
id(), cacheValue );
948 QVariant sortValue = fieldFormatter->
sortValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, f.
attribute( cache.sortFieldIndex ) );
949 cache.sortCache.insert( f.
id(), sortValue );
956 QString expressionString;
958 if ( cacheIndex >= mSortCaches.size() )
959 return expressionString;
961 const QgsExpression &expression = mSortCaches[cacheIndex].sortCacheExpression;
966 expressionString = QString();
968 return expressionString;
980 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...
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
QSet< QgsFeatureId > QgsFeatureIds
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 beforeRollBack()
Is 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.
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.
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.
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.
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.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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) ...
#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()
Is 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.
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.
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.
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
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.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be null.
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.