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 if ( !mResettingModel )
170 beginRemoveRows( parent, row, row + count - 1 );
174 QgsDebugMsgLevel( QStringLiteral(
"remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 );
178 for (
int i = row; i < row + count; i++ )
180 for ( SortCache &cache : mSortCaches )
181 cache.sortCache.remove( mRowIdMap[i] );
182 mIdRowMap.remove( mRowIdMap[i] );
183 mRowIdMap.remove( i );
187 int n = mRowIdMap.size() + count;
188 for (
int i = row + count; i < n; i++ )
191 mIdRowMap[id] -= count;
192 mRowIdMap[i - count] = id;
193 mRowIdMap.remove( i );
199 QgsDebugMsgLevel( QStringLiteral(
"after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );
201 for ( QHash<QgsFeatureId, int>::const_iterator it = mIdRowMap.constBegin(); it != mIdRowMap.constEnd(); ++it )
205 for ( QHash<int, QgsFeatureId>::const_iterator it = mRowIdMap.constBegin(); it != mRowIdMap.constEnd(); ++it )
210 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
212 if ( !mResettingModel )
218 void QgsAttributeTableModel::featureAdded(
QgsFeatureId fid )
223 if ( mFeat.
id() != fid )
224 featOk = loadFeatureAtId( fid );
228 for ( SortCache &cache : mSortCaches )
230 if ( cache.sortFieldIndex >= 0 )
233 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
234 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
235 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, mFeat.
attribute( cache.sortFieldIndex ) );
236 cache.sortCache.insert( mFeat.
id(), sortValue );
238 else if ( cache.sortCacheExpression.isValid() )
241 cache.sortCache[mFeat.
id()] = cache.sortCacheExpression.evaluate( &mExpressionContext );
246 if ( ! mIdRowMap.contains( fid ) )
248 int n = mRowIdMap.size();
249 if ( !mResettingModel )
250 beginInsertRows( QModelIndex(), n, n );
251 mIdRowMap.insert( fid, n );
252 mRowIdMap.insert( n, fid );
253 if ( !mResettingModel )
260 void QgsAttributeTableModel::updatedFields()
266 void QgsAttributeTableModel::editCommandEnded()
270 bulkEditCommandEnded( );
273 void QgsAttributeTableModel::attributeDeleted(
int idx )
276 for (
const SortCache &cache : mSortCaches )
278 if ( cache.sortCacheAttributes.contains( idx ) )
286 void QgsAttributeTableModel::layerDeleted()
288 mLayerCache =
nullptr;
291 mAttributeWidgetCaches.clear();
293 mWidgetFactories.clear();
294 mWidgetConfigs.clear();
295 mFieldFormatters.clear();
298 void QgsAttributeTableModel::fieldFormatterRemoved(
QgsFieldFormatter *fieldFormatter )
300 for (
int i = 0; i < mFieldFormatters.size(); ++i )
302 if ( mFieldFormatters.at( i ) == fieldFormatter )
307 void QgsAttributeTableModel::attributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
310 if ( mBulkEditCommandRunning )
312 mAttributeValueChanges.insert( QPair<QgsFeatureId, int>( fid, idx ), value );
315 QgsDebugMsgLevel( QStringLiteral(
"(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.
filterType() ), 2 );
317 for ( SortCache &cache : mSortCaches )
319 if ( cache.sortCacheAttributes.contains( idx ) )
321 if ( cache.sortFieldIndex == -1 )
323 if ( loadFeatureAtId( fid ) )
326 cache.sortCache[fid] = cache.sortCacheExpression.evaluate( &mExpressionContext );
332 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
333 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
334 QVariant sortValue = fieldFormatter->
representValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, value );
335 cache.sortCache.insert( fid, sortValue );
342 if ( loadFeatureAtId( fid ) )
347 if ( loadFeatureAtId( fid ) )
351 if ( !mIdRowMap.contains( fid ) )
364 if ( mIdRowMap.contains( fid ) )
375 void QgsAttributeTableModel::loadAttributes()
382 bool ins =
false, rm =
false;
387 mWidgetFactories.clear();
388 mAttributeWidgetCaches.clear();
389 mWidgetConfigs.clear();
391 for (
int idx = 0; idx < fields.
count(); ++idx )
397 mWidgetFactories.append( widgetFactory );
398 mWidgetConfigs.append( setup.
config() );
400 mFieldFormatters.append( fieldFormatter );
405 if ( mFieldCount + mExtraColumns < attributes.size() + mExtraColumns )
408 beginInsertColumns( QModelIndex(), mFieldCount + mExtraColumns, attributes.size() - 1 );
410 else if ( attributes.size() + mExtraColumns < mFieldCount + mExtraColumns )
413 beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount + mExtraColumns - 1 );
416 mFieldCount = attributes.size();
417 mAttributes = attributes;
419 for ( SortCache &cache : mSortCaches )
421 if ( cache.sortFieldIndex >= mAttributes.count() )
422 cache.sortFieldIndex = -1;
444 mResettingModel =
true;
466 if ( t.elapsed() > 1000 )
475 featureAdded( mFeat.
id() );
484 mResettingModel =
false;
490 if ( fieldName.isNull() )
492 mRowStylesMap.clear();
498 if ( fieldIndex == -1 )
503 emit dataChanged( index( 0, col ), index(
rowCount() - 1, col ) );
516 mRowIdMap.remove( rowA );
517 mRowIdMap.remove( rowB );
518 mRowIdMap.insert( rowA, b );
519 mRowIdMap.insert( rowB, a );
521 mIdRowMap.remove( a );
522 mIdRowMap.remove( b );
523 mIdRowMap.insert( a, rowB );
524 mIdRowMap.insert( b, rowA );
525 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
533 if ( !mIdRowMap.contains(
id ) )
535 QgsDebugMsg( QStringLiteral(
"idToRow: id %1 not in the map" ).arg(
id ) );
539 return mIdRowMap[id];
544 return index(
idToRow(
id ), 0 );
549 QModelIndexList indexes;
553 indexes.reserve( columns );
554 for (
int column = 0; column < columns; ++column )
556 indexes.append( index( row, column ) );
564 if ( !mRowIdMap.contains( row ) )
566 QgsDebugMsg( QStringLiteral(
"rowToId: row %1 not in the map" ).arg( row ) );
568 return std::numeric_limits<int>::min();
571 return mRowIdMap[row];
576 return mAttributes[col];
581 return mAttributes.indexOf( idx );
587 return mRowIdMap.size();
593 return std::max( 1, mFieldCount + mExtraColumns );
601 if ( role == Qt::DisplayRole )
603 if ( orientation == Qt::Vertical )
605 return QVariant( section );
607 else if ( section >= 0 && section < mFieldCount )
610 return QVariant( attributeName );
614 return tr(
"extra column" );
617 else if ( role == Qt::ToolTipRole )
619 if ( orientation == Qt::Vertical )
622 return tr(
"Feature ID: %1" ).arg(
rowToId( section ) );
638 if ( !index.isValid() || !
layer() ||
639 ( role != Qt::TextAlignmentRole
640 && role != Qt::DisplayRole
641 && role != Qt::ToolTipRole
642 && role != Qt::EditRole
645 #
if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
646 && role != Qt::BackgroundColorRole
647 && role != Qt::TextColorRole
649 && role != Qt::BackgroundRole
650 && role != Qt::ForegroundRole
652 && role != Qt::DecorationRole
653 && role != Qt::FontRole
664 if ( index.column() >= mFieldCount )
667 int fieldId = mAttributes.at( index.column() );
674 unsigned long cacheIndex = role -
SortRole;
675 if ( cacheIndex < mSortCaches.size() )
676 return mSortCaches.at( cacheIndex ).sortCache.value( rowId );
683 if ( role == Qt::TextAlignmentRole )
685 return QVariant( mFieldFormatters.at( index.column() )->alignmentFlag(
layer(), fieldId, mWidgetConfigs.at( index.column() ) ) | Qt::AlignVCenter );
688 if ( mFeat.
id() != rowId || !mFeat.
isValid() )
690 if ( !loadFeatureAtId( rowId ) )
691 return QVariant(
"ERROR" );
693 if ( mFeat.
id() != rowId )
694 return QVariant(
"ERROR" );
697 QVariant val = mFeat.
attribute( fieldId );
701 case Qt::DisplayRole:
702 case Qt::ToolTipRole:
703 return mFieldFormatters.at( index.column() )->representValue(
layer(),
705 mWidgetConfigs.at( index.column() ),
706 mAttributeWidgetCaches.at( index.column() ),
712 case Qt::BackgroundRole:
713 #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
714 case Qt::TextColorRole:
716 case Qt::ForegroundRole:
718 case Qt::DecorationRole:
722 QList<QgsConditionalStyle> styles;
723 if ( mRowStylesMap.contains( mFeat.
id() ) )
725 styles = mRowStylesMap[mFeat.
id()];
730 mRowStylesMap.insert( mFeat.
id(), styles );
736 styles.insert( 0, rowstyle );
743 #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
749 if ( role == Qt::DecorationRole )
751 if ( role == Qt::FontRole )
766 if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !
layer()->isEditable() )
769 if ( !
layer()->isModified() )
772 mRowStylesMap.remove( mFeat.
id() );
779 if ( !index.isValid() )
780 return Qt::ItemIsEnabled;
782 if ( index.column() >= mFieldCount || !
layer() )
783 return Qt::NoItemFlags;
785 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
787 const int fieldIndex = mAttributes[index.column()];
791 flags |= Qt::ItemIsEditable;
796 void QgsAttributeTableModel::bulkEditCommandStarted()
798 mBulkEditCommandRunning =
true;
799 mAttributeValueChanges.clear();
802 void QgsAttributeTableModel::bulkEditCommandEnded()
804 mBulkEditCommandRunning =
false;
807 int changeCount( mAttributeValueChanges.count() );
808 bool fullModelUpdate = changeCount > mLayerCache->
cacheSize() ||
811 QgsDebugMsgLevel( QStringLiteral(
"Bulk edit command ended with %1 modified rows over (%4), cache size is %2, starting %3 update." )
814 .arg( fullModelUpdate ? QStringLiteral(
"full" ) : QStringLiteral(
"incremental" ) )
818 if ( fullModelUpdate )
830 const auto keys = mAttributeValueChanges.keys();
831 for (
const auto &key : keys )
833 attributeValueChanged( key.first, key.second, mAttributeValueChanges.value( key ) );
834 int row(
idToRow( key.first ) );
836 minRow = std::min<int>( row, minRow );
837 minCol = std::min<int>( col, minCol );
838 maxRow = std::max<int>( row, maxRow );
839 maxCol = std::max<int>( col, maxCol );
841 emit dataChanged( createIndex( minRow, minCol ), createIndex( maxRow, maxCol ) );
843 mAttributeValueChanges.clear();
848 mFeat.
setId( std::numeric_limits<int>::min() );
849 emit dataChanged( index1, index2 );
870 for (
int i = 0; i < mAttributes.size(); i++ )
872 f.
setAttribute( mAttributes[i],
data( index( idx.row(), i ), Qt::EditRole ) );
880 if ( column == -1 || column >= mAttributes.count() )
892 if ( cacheIndex >= mSortCaches.size() )
894 mSortCaches.resize( cacheIndex + 1 );
896 SortCache &cache = mSortCaches[cacheIndex];
897 cache.sortCache.clear();
898 cache.sortCacheAttributes.clear();
899 cache.sortFieldIndex = -1;
900 if ( !expressionString.isEmpty() )
901 cache.sortCacheExpression =
QgsExpression( expressionString );
910 QVariant widgetCache;
911 QVariantMap widgetConfig;
913 if ( cache.sortCacheExpression.isField() )
919 if ( cache.sortFieldIndex == -1 )
921 cache.sortCacheExpression.prepare( &mExpressionContext );
923 const QSet<QString> &referencedColumns = cache.sortCacheExpression.referencedColumns();
925 for (
const QString &col : referencedColumns )
932 cache.sortCacheAttributes.append( cache.sortFieldIndex );
934 widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
935 widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
936 fieldFormatter = mFieldFormatters.at( cache.sortFieldIndex );
947 if ( cache.sortFieldIndex == -1 )
950 const QVariant cacheValue = cache.sortCacheExpression.evaluate( &mExpressionContext );
951 cache.sortCache.insert( f.
id(), cacheValue );
955 QVariant sortValue = fieldFormatter->
sortValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, f.
attribute( cache.sortFieldIndex ) );
956 cache.sortCache.insert( f.
id(), sortValue );
963 QString expressionString;
965 if ( cacheIndex >= mSortCaches.size() )
966 return expressionString;
968 const QgsExpression &expression = mSortCaches[cacheIndex].sortCacheExpression;
973 expressionString = QString();
975 return expressionString;
987 return mFeatureRequest;