Skip to content

Commit

Permalink
[FIX #7609] Fetch and cache data for sorting column in one query
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Apr 18, 2013
1 parent 046fbee commit 66fadee
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 7 deletions.
6 changes: 6 additions & 0 deletions src/gui/attributetable/qgsattributetablefiltermodel.cpp
Expand Up @@ -86,6 +86,12 @@ bool QgsAttributeTableFilterModel::lessThan( const QModelIndex &left, const QMod
return false;
}

void QgsAttributeTableFilterModel::sort( int column, Qt::SortOrder order )
{
masterModel()->prefetchColumnData( column );
QSortFilterProxyModel::sort( column, order );
}

void QgsAttributeTableFilterModel::setSelectedOnTop( bool selectedOnTop )
{
if ( mSelectedOnTop != selectedOnTop )
Expand Down
9 changes: 9 additions & 0 deletions src/gui/attributetable/qgsattributetablefiltermodel.h
Expand Up @@ -142,6 +142,15 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
*/
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const;

/**
* Sort by the given column using the given order.
* Prefetches all the data from the layer to speed up sorting.
*
* @param column The column which should be sorted
* @param order The order ( Qt::AscendingOrder or Qt::DescendingOrder )
*/
virtual void sort( int column, Qt::SortOrder order = Qt::AscendingOrder );

public slots:
/**
* Is called upon every change of the visible extents on the map canvas.
Expand Down
55 changes: 49 additions & 6 deletions src/gui/attributetable/qgsattributetablemodel.cpp
Expand Up @@ -33,6 +33,7 @@
QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayerCache *layerCache, QObject *parent )
: QAbstractTableModel( parent )
, mLayerCache( layerCache )
, mCachedField( -1 )
{
QgsDebugMsg( "entered." );

Expand Down Expand Up @@ -80,7 +81,7 @@ bool QgsAttributeTableModel::loadFeatureAtId( QgsFeatureId fid ) const

void QgsAttributeTableModel::featureDeleted( QgsFeatureId fid )
{
QgsDebugMsgLevel( QString( "deleted fid=%1 => row=%2" ).arg( fid ).arg( idToRow( fid ) ), 3 );
prefetchColumnData( -1 ); // Invalidate cached column data

int row = idToRow( fid );

Expand Down Expand Up @@ -131,8 +132,7 @@ bool QgsAttributeTableModel::removeRows( int row, int count, const QModelIndex &

void QgsAttributeTableModel::featureAdded( QgsFeatureId fid, bool newOperation )
{
QgsDebugMsgLevel( QString( "feature %1 added (%2, rows %3, ids %4)" ).arg( fid ).arg( newOperation ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );

prefetchColumnData( -1 ); // Invalidate cached column data
int n = mRowIdMap.size();
if ( newOperation )
beginInsertRows( QModelIndex(), n, n );
Expand Down Expand Up @@ -172,6 +172,9 @@ void QgsAttributeTableModel::layerDeleted()

void QgsAttributeTableModel::attributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value )
{
if ( mCachedField == idx )
mFieldCache[ fid ] = value;

if ( fid == mFeat.id() )
{
mFeat.setValid( false );
Expand Down Expand Up @@ -483,17 +486,30 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons
return QVariant( Qt::AlignLeft );
}

const QVariant* pVal = NULL;

// if we don't have the row in current cache, load it from layer first
if ( mFeat.id() != rowId || !mFeat.isValid() )
{
if ( !loadFeatureAtId( rowId ) )
if ( mCachedField == fieldId )
{
const QVariant& val = mFieldCache[rowId];
pVal = &val;
}
else if ( !loadFeatureAtId( rowId ) )
return QVariant( "ERROR" );
}

if ( mFeat.id() != rowId )
if ( pVal == NULL && mFeat.id() != rowId )
return QVariant( "ERROR" );

const QVariant &val = mFeat.attribute( fieldId );
if ( !pVal )
{
const QVariant& val = mFeat.attribute( fieldId );
pVal =&val;
}

const QVariant& val = *pVal;

// For sorting return unprocessed value
if ( SortRole == role )
Expand Down Expand Up @@ -599,3 +615,30 @@ QgsFeature QgsAttributeTableModel::feature( const QModelIndex &idx ) const

return f;
}

void QgsAttributeTableModel::prefetchColumnData( int column )
{
mFieldCache.clear();

if ( column == -1 )
{
mCachedField = -1;
}
else
{
int fieldId = mAttributes[ column ];
const QgsFields& fields = layer()->pendingFields();
QStringList fldNames;
fldNames << fields[ fieldId ].name();

QgsFeatureIterator it = mLayerCache->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( fldNames, fields ) );

QgsFeature f;
while ( it.nextFeature( f ) )
{
mFieldCache.insert( f.id(), f.attribute( fieldId ) );
}

mCachedField = fieldId;
}
}
19 changes: 18 additions & 1 deletion src/gui/attributetable/qgsattributetablemodel.h
Expand Up @@ -22,6 +22,7 @@
#include <QObject>
#include <QHash>
#include <QQueue>
#include <QMap>

#include "qgsvectorlayer.h" // QgsAttributeList
#include "qgsvectorlayercache.h"
Expand Down Expand Up @@ -173,9 +174,20 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
void executeAction( int action, const QModelIndex &idx ) const;

/**
* return feature attributes at given index */
* Return the feature attributes at given model index
* @return feature attributes at given model index
*/
QgsFeature feature( const QModelIndex &idx ) const;

/**
* Caches the entire data for one column. This should be called prior to sorting,
* so the data does not have to be fetched for every single comparison.
* Specify -1 as column to invalidate the cache
*
* @param column The column index of the field to catch
*/
void prefetchColumnData( int column );

signals:
/**
* Model has been changed
Expand Down Expand Up @@ -245,6 +257,11 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
virtual bool loadFeatureAtId( QgsFeatureId fid ) const;

QgsFeatureRequest mFeatureRequest;

/** The currently cached column */
int mCachedField;
/** Allows to cache one specific column (used for sorting) */
QMap<QgsFeatureId, QVariant> mFieldCache;
};


Expand Down

0 comments on commit 66fadee

Please sign in to comment.