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 && role != Qt::BackgroundColorRole
646 && role != Qt::TextColorRole
647 && role != Qt::DecorationRole
648 && role != Qt::FontRole
659 if ( index.column() >= mFieldCount )
662 int fieldId = mAttributes.at( index.column() );
669 unsigned long cacheIndex = role -
SortRole;
670 if ( cacheIndex < mSortCaches.size() )
671 return mSortCaches.at( cacheIndex ).sortCache.value( rowId );
678 if ( role == Qt::TextAlignmentRole )
680 return QVariant( mFieldFormatters.at( index.column() )->alignmentFlag(
layer(), fieldId, mWidgetConfigs.at( index.column() ) ) | Qt::AlignVCenter );
683 if ( mFeat.
id() != rowId || !mFeat.
isValid() )
685 if ( !loadFeatureAtId( rowId ) )
686 return QVariant(
"ERROR" );
688 if ( mFeat.
id() != rowId )
689 return QVariant(
"ERROR" );
692 QVariant val = mFeat.
attribute( fieldId );
696 case Qt::DisplayRole:
697 case Qt::ToolTipRole:
698 return mFieldFormatters.at( index.column() )->representValue(
layer(),
700 mWidgetConfigs.at( index.column() ),
701 mAttributeWidgetCaches.at( index.column() ),
707 case Qt::BackgroundRole:
708 case Qt::TextColorRole:
709 case Qt::DecorationRole:
713 QList<QgsConditionalStyle> styles;
714 if ( mRowStylesMap.contains( mFeat.
id() ) )
716 styles = mRowStylesMap[mFeat.
id()];
721 mRowStylesMap.insert( mFeat.
id(), styles );
727 styles.insert( 0, rowstyle );
736 if ( role == Qt::DecorationRole )
738 if ( role == Qt::FontRole )
753 if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !
layer()->isEditable() )
756 if ( !
layer()->isModified() )
759 mRowStylesMap.remove( mFeat.
id() );
766 if ( !index.isValid() )
767 return Qt::ItemIsEnabled;
769 if ( index.column() >= mFieldCount || !
layer() )
770 return Qt::NoItemFlags;
772 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
774 const int fieldIndex = mAttributes[index.column()];
778 flags |= Qt::ItemIsEditable;
783 void QgsAttributeTableModel::bulkEditCommandStarted()
785 mBulkEditCommandRunning =
true;
786 mAttributeValueChanges.clear();
789 void QgsAttributeTableModel::bulkEditCommandEnded()
791 mBulkEditCommandRunning =
false;
794 int changeCount( mAttributeValueChanges.count() );
795 bool fullModelUpdate = changeCount > mLayerCache->
cacheSize() ||
798 QgsDebugMsgLevel( QStringLiteral(
"Bulk edit command ended with %1 modified rows over (%4), cache size is %2, starting %3 update." )
801 .arg( fullModelUpdate ? QStringLiteral(
"full" ) : QStringLiteral(
"incremental" ) )
805 if ( fullModelUpdate )
817 const auto keys = mAttributeValueChanges.keys();
818 for (
const auto &key : keys )
820 attributeValueChanged( key.first, key.second, mAttributeValueChanges.value( key ) );
821 int row(
idToRow( key.first ) );
823 minRow = std::min<int>( row, minRow );
824 minCol = std::min<int>( col, minCol );
825 maxRow = std::max<int>( row, maxRow );
826 maxCol = std::max<int>( col, maxCol );
828 emit dataChanged( createIndex( minRow, minCol ), createIndex( maxRow, maxCol ) );
830 mAttributeValueChanges.clear();
835 mFeat.
setId( std::numeric_limits<int>::min() );
836 emit dataChanged( index1, index2 );
857 for (
int i = 0; i < mAttributes.size(); i++ )
859 f.
setAttribute( mAttributes[i],
data( index( idx.row(), i ), Qt::EditRole ) );
867 if ( column == -1 || column >= mAttributes.count() )
879 if ( cacheIndex >= mSortCaches.size() )
881 mSortCaches.resize( cacheIndex + 1 );
883 SortCache &cache = mSortCaches[cacheIndex];
884 cache.sortCache.clear();
885 cache.sortCacheAttributes.clear();
886 cache.sortFieldIndex = -1;
887 if ( !expressionString.isEmpty() )
888 cache.sortCacheExpression =
QgsExpression( expressionString );
897 QVariant widgetCache;
898 QVariantMap widgetConfig;
900 if ( cache.sortCacheExpression.isField() )
906 if ( cache.sortFieldIndex == -1 )
908 cache.sortCacheExpression.prepare( &mExpressionContext );
910 const QSet<QString> &referencedColumns = cache.sortCacheExpression.referencedColumns();
912 for (
const QString &col : referencedColumns )
919 cache.sortCacheAttributes.append( cache.sortFieldIndex );
921 widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
922 widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
923 fieldFormatter = mFieldFormatters.at( cache.sortFieldIndex );
934 if ( cache.sortFieldIndex == -1 )
937 const QVariant cacheValue = cache.sortCacheExpression.evaluate( &mExpressionContext );
938 cache.sortCache.insert( f.
id(), cacheValue );
942 QVariant sortValue = fieldFormatter->
sortValue(
layer(), cache.sortFieldIndex, widgetConfig, widgetCache, f.
attribute( cache.sortFieldIndex ) );
943 cache.sortCache.insert( f.
id(), sortValue );
950 QString expressionString;
952 if ( cacheIndex >= mSortCaches.size() )
953 return expressionString;
955 const QgsExpression &expression = mSortCaches[cacheIndex].sortCacheExpression;
960 expressionString = QString();
962 return expressionString;
974 return mFeatureRequest;