23 #include "qgsexpression.h" 37 #include "qgsexpressionnodeimpl.h" 47 : QAbstractTableModel( parent )
48 , mLayerCache( layerCache )
50 , mSortFieldIndex( -1 )
60 mFeat.
setId( std::numeric_limits<int>::min() );
62 if ( !
layer()->isSpatial() )
76 bool QgsAttributeTableModel::loadFeatureAtId(
QgsFeatureId fid )
const 80 if ( fid == std::numeric_limits<int>::min() )
99 void QgsAttributeTableModel::featuresDeleted(
const QgsFeatureIds &fids )
105 QgsDebugMsgLevel( QString(
"(%2) fid: %1, size: %3" ).arg( fid ).arg( mFeatureRequest.
filterType() ).arg( mIdRowMap.size() ), 4 );
112 std::sort( rows.begin(), rows.end() );
116 int currentRowCount = 0;
120 Q_FOREACH (
int row, rows )
123 qDebug() <<
"Row: " << row <<
", begin " << beginRow <<
", last " << lastRow <<
", current " << currentRowCount <<
", removed " << removedRows;
130 if ( row != lastRow + 1 && lastRow != -1 )
132 if ( rows.count() > 100 && currentRowCount < 10 )
137 removeRows( beginRow - removedRows, currentRowCount );
140 removedRows += currentRowCount;
150 removeRows( beginRow - removedRows, currentRowCount );
158 if ( row < 0 || count < 1 )
161 beginRemoveRows( parent, row, row + count - 1 );
165 QgsDebugMsgLevel( QString(
"remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 );
169 for (
int i = row; i < row + count; i++ )
171 mSortCache.remove( mRowIdMap[i] );
172 mIdRowMap.remove( mRowIdMap[i] );
173 mRowIdMap.remove( i );
177 int n = mRowIdMap.size() + count;
178 for (
int i = row + count; i < n; i++ )
181 mIdRowMap[id] -= count;
182 mRowIdMap[i - count] = id;
183 mRowIdMap.remove( i );
189 QgsDebugMsgLevel( QString(
"after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );
191 for ( QHash<QgsFeatureId, int>::const_iterator it = mIdRowMap.constBegin(); it != mIdRowMap.constEnd(); ++it )
195 for ( QHash<int, QgsFeatureId>::const_iterator it = mRowIdMap.constBegin(); it != mRowIdMap.constEnd(); ++it )
200 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
207 void QgsAttributeTableModel::featureAdded(
QgsFeatureId fid,
bool resettingModel )
212 if ( mFeat.
id() != fid )
213 featOk = loadFeatureAtId( fid );
217 if ( mSortFieldIndex >= 0 )
220 const QVariant &widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
221 const QVariantMap &widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
222 QVariant sortValue = fieldFormatter->
representValue(
layer(), mSortFieldIndex, widgetConfig, widgetCache, mFeat.
attribute( mSortFieldIndex ) );
223 mSortCache.insert( mFeat.
id(), sortValue );
225 else if ( mSortCacheExpression.isValid() )
228 mSortCache[mFeat.
id()] = mSortCacheExpression.evaluate( &mExpressionContext );
232 if ( ! mIdRowMap.contains( fid ) )
234 int n = mRowIdMap.size();
235 if ( !resettingModel )
236 beginInsertRows( QModelIndex(), n, n );
237 mIdRowMap.insert( fid, n );
238 mRowIdMap.insert( n, fid );
239 if ( !resettingModel )
246 void QgsAttributeTableModel::updatedFields()
252 void QgsAttributeTableModel::editCommandEnded()
256 mChangedCellBounds = QRect();
259 void QgsAttributeTableModel::attributeDeleted(
int idx )
261 if ( mSortCacheAttributes.contains( idx ) )
265 void QgsAttributeTableModel::layerDeleted()
267 mLayerCache =
nullptr;
270 mAttributeWidgetCaches.clear();
272 mWidgetFactories.clear();
273 mWidgetConfigs.clear();
274 mFieldFormatters.clear();
277 void QgsAttributeTableModel::fieldFormatterRemoved(
QgsFieldFormatter *fieldFormatter )
279 for (
int i = 0; i < mFieldFormatters.size(); ++i )
281 if ( mFieldFormatters.at( i ) == fieldFormatter )
286 void QgsAttributeTableModel::attributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
288 QgsDebugMsgLevel( QString(
"(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.
filterType() ), 3 );
290 if ( mSortCacheAttributes.contains( idx ) )
292 if ( mSortFieldIndex == -1 )
294 if ( loadFeatureAtId( fid ) )
297 mSortCache[fid] = mSortCacheExpression.evaluate( &mExpressionContext );
303 const QVariant &widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
304 const QVariantMap &widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
305 QVariant sortValue = fieldFormatter->
representValue(
layer(), mSortFieldIndex, widgetConfig, widgetCache, value );
306 mSortCache.insert( fid, sortValue );
312 if ( loadFeatureAtId( fid ) )
317 if ( loadFeatureAtId( fid ) )
321 if ( !mIdRowMap.contains( fid ) )
334 if ( mIdRowMap.contains( fid ) )
345 void QgsAttributeTableModel::loadAttributes()
352 bool ins =
false, rm =
false;
357 mWidgetFactories.clear();
358 mAttributeWidgetCaches.clear();
359 mWidgetConfigs.clear();
361 for (
int idx = 0; idx < fields.
count(); ++idx )
369 mWidgetFactories.append( widgetFactory );
370 mWidgetConfigs.append( setup.
config() );
372 mFieldFormatters.append( fieldFormatter );
378 if ( mFieldCount + mExtraColumns < attributes.size() + mExtraColumns )
381 beginInsertColumns( QModelIndex(), mFieldCount + mExtraColumns, attributes.size() - 1 );
383 else if ( attributes.size() + mExtraColumns < mFieldCount + mExtraColumns )
386 beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount + mExtraColumns - 1 );
389 mFieldCount = attributes.size();
390 mAttributes = attributes;
392 if ( mSortFieldIndex >= mAttributes.count() )
393 mSortFieldIndex = -1;
431 if ( t.elapsed() > 1000 )
440 featureAdded( mFeat.
id(), true );
452 if ( fieldName.isNull() )
454 mRowStylesMap.clear();
460 if ( fieldIndex == -1 )
465 emit dataChanged( index( 0, col ), index(
rowCount() - 1, col ) );
478 mRowIdMap.remove( rowA );
479 mRowIdMap.remove( rowB );
480 mRowIdMap.insert( rowA, b );
481 mRowIdMap.insert( rowB, a );
483 mIdRowMap.remove( a );
484 mIdRowMap.remove( b );
485 mIdRowMap.insert( a, rowB );
486 mIdRowMap.insert( b, rowA );
487 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
495 if ( !mIdRowMap.contains(
id ) )
497 QgsDebugMsg( QString(
"idToRow: id %1 not in the map" ).arg(
id ) );
501 return mIdRowMap[id];
506 return index(
idToRow(
id ), 0 );
511 QModelIndexList indexes;
515 indexes.reserve( columns );
516 for (
int column = 0; column < columns; ++column )
518 indexes.append( index( row, column ) );
526 if ( !mRowIdMap.contains( row ) )
528 QgsDebugMsg( QString(
"rowToId: row %1 not in the map" ).arg( row ) );
530 return std::numeric_limits<int>::min();
533 return mRowIdMap[row];
538 return mAttributes[col];
543 return mAttributes.indexOf( idx );
549 return mRowIdMap.size();
555 return std::max( 1, mFieldCount + mExtraColumns );
563 if ( role == Qt::DisplayRole )
565 if ( orientation == Qt::Vertical )
567 return QVariant( section );
569 else if ( section >= 0 && section < mFieldCount )
571 QString attributeName =
layer()->
fields().
at( mAttributes.at( section ) ).displayName();
572 return QVariant( attributeName );
576 return tr(
"extra column" );
579 else if ( role == Qt::ToolTipRole )
581 if ( orientation == Qt::Vertical )
584 return tr(
"Feature ID: %1" ).arg(
rowToId( section ) );
600 if ( !index.isValid() || !
layer() ||
601 ( role != Qt::TextAlignmentRole
602 && role != Qt::DisplayRole
603 && role != Qt::ToolTipRole
604 && role != Qt::EditRole
608 && role != Qt::BackgroundColorRole
609 && role != Qt::TextColorRole
610 && role != Qt::DecorationRole
611 && role != Qt::FontRole
621 if ( index.column() >= mFieldCount )
624 int fieldId = mAttributes.at( index.column() );
631 return mSortCache[rowId];
636 if ( role == Qt::TextAlignmentRole )
638 return QVariant( mFieldFormatters.at( index.column() )->alignmentFlag(
layer(), fieldId, mWidgetConfigs.at( index.column() ) ) | Qt::AlignVCenter );
641 if ( mFeat.
id() != rowId || !mFeat.
isValid() )
643 if ( !loadFeatureAtId( rowId ) )
644 return QVariant(
"ERROR" );
646 if ( mFeat.
id() != rowId )
647 return QVariant(
"ERROR" );
650 QVariant val = mFeat.
attribute( fieldId );
654 case Qt::DisplayRole:
655 case Qt::ToolTipRole:
656 return mFieldFormatters.at( index.column() )->representValue(
layer(), fieldId, mWidgetConfigs.at( index.column() ),
657 mAttributeWidgetCaches.at( index.column() ), val );
662 case Qt::BackgroundColorRole:
663 case Qt::TextColorRole:
664 case Qt::DecorationRole:
668 QList<QgsConditionalStyle> styles;
669 if ( mRowStylesMap.contains( index.row() ) )
671 styles = mRowStylesMap[index.row()];
676 mRowStylesMap.insert( index.row(), styles );
682 styles.insert( 0, rowstyle );
691 if ( role == Qt::DecorationRole )
693 if ( role == Qt::FontRole )
708 if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !
layer()->
isEditable() )
714 if ( mChangedCellBounds.isNull() )
716 mChangedCellBounds = QRect( index.column(), index.row(), 1, 1 );
720 if ( index.column() < mChangedCellBounds.left() )
722 mChangedCellBounds.setLeft( index.column() );
724 if ( index.row() < mChangedCellBounds.top() )
726 mChangedCellBounds.setTop( index.row() );
728 if ( index.column() > mChangedCellBounds.right() )
730 mChangedCellBounds.setRight( index.column() );
732 if ( index.row() > mChangedCellBounds.bottom() )
734 mChangedCellBounds.setBottom( index.row() );
743 if ( !index.isValid() )
744 return Qt::ItemIsEnabled;
746 if ( index.column() >= mFieldCount || !
layer() )
747 return Qt::NoItemFlags;
749 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
751 bool editable =
false;
752 const int fieldIndex = mAttributes[index.column()];
760 editable = fieldIsEditable( *info->
joinLayer(), srcFieldIndex, fid );
763 editable = fieldIsEditable( *
layer(), fieldIndex, fid );
766 flags |= Qt::ItemIsEditable;
780 mFeat.
setId( std::numeric_limits<int>::min() );
781 emit dataChanged( index1, index2 );
802 for (
int i = 0; i < mAttributes.size(); i++ )
804 f.
setAttribute( mAttributes[i],
data( index( idx.row(), i ), Qt::EditRole ) );
812 if ( column == -1 || column >= mAttributes.count() )
825 mSortCacheAttributes.clear();
826 mSortFieldIndex = -1;
827 if ( !expressionString.isEmpty() )
828 mSortCacheExpression = QgsExpression( expressionString );
832 mSortCacheExpression = QgsExpression();
837 QVariant widgetCache;
838 QVariantMap widgetConfig;
840 if ( mSortCacheExpression.isField() )
842 QString fieldName =
static_cast<const QgsExpressionNodeColumnRef *
>( mSortCacheExpression.rootNode() )->name();
846 if ( mSortFieldIndex == -1 )
848 mSortCacheExpression.prepare( &mExpressionContext );
850 Q_FOREACH (
const QString &col, mSortCacheExpression.referencedColumns() )
857 mSortCacheAttributes.append( mSortFieldIndex );
859 widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
860 widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
861 fieldFormatter = mFieldFormatters.at( mSortFieldIndex );
872 if ( mSortFieldIndex == -1 )
875 mSortCache.insert( f.
id(), mSortCacheExpression.evaluate( &mExpressionContext ) );
879 QVariant sortValue = fieldFormatter->
sortValue(
layer(), mSortFieldIndex, widgetConfig, widgetCache, f.
attribute( mSortFieldIndex ) );
880 mSortCache.insert( f.
id(), sortValue );
887 if ( mSortCacheExpression.isValid() )
888 return mSortCacheExpression.expression();
902 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.
QgsActionManager * actions()
Get 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()
Get the registry of available field formatters.
FieldOrigin fieldOrigin(int fieldIdx) const
Get field's origin (value from an enumeration)
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
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
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName)
Returns the conditional styles set for the field UI properties.
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
Return 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
Return 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
Return the conditional styles that are set for this layer.
QgsField at(int i) const
Get 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
Return 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.
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.
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)...
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
Get 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()
Accessor to the join buffer object.
QModelIndexList idToIndexList(QgsFeatureId id) const
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
get column from field index
int fieldIdx(int col) const
get 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.
QString sortCacheExpression() const
The expression which was used to fill the sorting cache.
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.
void prefetchSortData(const QString &expression)
Prefetches the entire data for one expression.
Qt::ItemFlags flags(const QModelIndex &index) const override
Returns item flags for the index.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Set flags that affect how features will be fetched.