Skip to content

Commit

Permalink
QgsFeatureListModel is sortable by display expression
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed May 17, 2018
1 parent 14cefe3 commit f1770c7
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 34 deletions.
Expand Up @@ -102,8 +102,6 @@ for a meaningful error message.
virtual QItemSelection mapSelectionFromMaster( const QItemSelection &selection ) const;
virtual QItemSelection mapSelectionToMaster( const QItemSelection &selection ) const;

virtual QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const;

virtual QModelIndex parent( const QModelIndex &child ) const;

virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const;
Expand All @@ -115,6 +113,25 @@ for a meaningful error message.

QModelIndexList fidToIndexList( QgsFeatureId fid );

bool sortByDisplayExpression() const;
%Docstring
Sort this model by its display expression.

.. versionadded:: 3.2
%End

void setSortByDisplayExpression( bool sortByDisplayExpression );
%Docstring
Sort this model by its display expression.

.. note::

Not compatible with injectNull, if sorting by display expression is enabled,
injectNull will automatically turned off.

.. versionadded:: 3.2
%End

public slots:
void onBeginRemoveRows( const QModelIndex &parent, int first, int last );
void onEndRemoveRows( const QModelIndex &parent, int first, int last );
Expand Down
122 changes: 92 additions & 30 deletions src/gui/attributetable/qgsfeaturelistmodel.cpp
Expand Up @@ -30,12 +30,13 @@ QgsFeatureListModel::QgsFeatureListModel( QgsAttributeTableFilterModel *sourceMo

void QgsFeatureListModel::setSourceModel( QgsAttributeTableFilterModel *sourceModel )
{
QAbstractProxyModel::setSourceModel( sourceModel );
QSortFilterProxyModel::setSourceModel( sourceModel );
mExpressionContext = sourceModel->layer()->createExpressionContext();
mFilterModel = sourceModel;

if ( mFilterModel )
{
#if 0
// rewire (filter-)change events in the source model so this proxy reflects the changes
connect( mFilterModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &QgsFeatureListModel::onBeginRemoveRows );
connect( mFilterModel, &QAbstractItemModel::rowsRemoved, this, &QgsFeatureListModel::onEndRemoveRows );
Expand All @@ -46,6 +47,7 @@ void QgsFeatureListModel::setSourceModel( QgsAttributeTableFilterModel *sourceMo
connect( mFilterModel, &QAbstractItemModel::layoutChanged, this, &QAbstractItemModel::layoutChanged );
connect( mFilterModel, &QAbstractItemModel::modelAboutToBeReset, this, &QAbstractItemModel::modelAboutToBeReset );
connect( mFilterModel, &QAbstractItemModel::modelReset, this, &QAbstractItemModel::modelReset );
#endif
}
}

Expand All @@ -61,7 +63,7 @@ QgsFeatureId QgsFeatureListModel::idxToFid( const QModelIndex &index ) const

QModelIndex QgsFeatureListModel::fidToIdx( const QgsFeatureId fid ) const
{
return mFilterModel->mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
return mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
}

QVariant QgsFeatureListModel::data( const QModelIndex &index, int role ) const
Expand Down Expand Up @@ -192,12 +194,15 @@ Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const

void QgsFeatureListModel::setInjectNull( bool injectNull )
{
if ( mInjectNull != injectNull )
{
beginResetModel();
mInjectNull = injectNull;
endResetModel();
}
if ( mInjectNull == injectNull )
return;

if ( injectNull )
setSortByDisplayExpression( false );

beginResetModel();
mInjectNull = injectNull;
endResetModel();
}

bool QgsFeatureListModel::injectNull()
Expand All @@ -224,7 +229,12 @@ bool QgsFeatureListModel::setDisplayExpression( const QString &expression )

mDisplayExpression = exp;

if ( mSortByDisplayExpression )
masterModel()->prefetchSortData( expression, 1 );

emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );

invalidate();
return true;
}

Expand Down Expand Up @@ -269,24 +279,63 @@ void QgsFeatureListModel::onEndInsertRows( const QModelIndex &parent, int first,
endInsertRows();
}

bool QgsFeatureListModel::sortByDisplayExpression() const
{
return mSortByDisplayExpression;
}

void QgsFeatureListModel::setSortByDisplayExpression( bool sortByDisplayExpression )
{
mSortByDisplayExpression = sortByDisplayExpression;

// If we are sorting by display expression, we do not support injected null
if ( sortByDisplayExpression )
setInjectNull( false );

setSortRole( QgsAttributeTableModel::SortRole + 1 );
setDynamicSortFilter( mSortByDisplayExpression );
sort( 0 );
}

QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
{
if ( !proxyIndex.isValid() )
return QModelIndex();
QModelIndex masterIndex;

int offset = mInjectNull ? 1 : 0;
if ( proxyIndex.isValid() )
{
if ( mSortByDisplayExpression )
{
masterIndex = mFilterModel->mapToMaster( mapToSource( proxyIndex ) );
}
else
{
int offset = mInjectNull ? 1 : 0;

return mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
masterIndex = mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
}
}
return masterIndex;
}

QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &sourceIndex ) const
QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &masterIndex ) const
{
if ( !sourceIndex.isValid() )
return QModelIndex();
QModelIndex proxyIndex;

int offset = mInjectNull ? 1 : 0;
if ( masterIndex.isValid() )
{
if ( mSortByDisplayExpression )
{
proxyIndex = mapFromSource( mFilterModel->mapFromMaster( masterIndex ) );
}
else
{
int offset = mInjectNull ? 1 : 0;

return createIndex( mFilterModel->mapFromMaster( masterIndex ).row() + offset, 0 );
}
}

return createIndex( mFilterModel->mapFromMaster( sourceIndex ).row() + offset, 0 );
return proxyIndex;
}

QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection &selection ) const
Expand All @@ -303,27 +352,40 @@ QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection &

QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
{
if ( !proxyIndex.isValid() )
return QModelIndex();
QModelIndex sourceIndex;

int offset = mInjectNull ? 1 : 0;
if ( mSortByDisplayExpression )
{
sourceIndex = QSortFilterProxyModel::mapToSource( proxyIndex );
}
else
{
if ( !proxyIndex.isValid() )
return QModelIndex();

return sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
}
int offset = mInjectNull ? 1 : 0;

QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
{
if ( !sourceIndex.isValid() )
return QModelIndex();
sourceIndex = sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
}

return createIndex( sourceIndex.row(), 0 );
return sourceIndex;
}

QModelIndex QgsFeatureListModel::index( int row, int column, const QModelIndex &parent ) const
QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
{
Q_UNUSED( parent )
QModelIndex proxyIndex;

if ( mSortByDisplayExpression )
{
proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
}
else
{
if ( sourceIndex.isValid() )
proxyIndex = createIndex( sourceIndex.row(), 0 );
}

return createIndex( row, column );
return proxyIndex;
}

QModelIndex QgsFeatureListModel::parent( const QModelIndex &child ) const
Expand Down
20 changes: 18 additions & 2 deletions src/gui/attributetable/qgsfeaturelistmodel.h
Expand Up @@ -56,7 +56,7 @@ class GUI_EXPORT QgsFeatureListModel : public QSortFilterProxyModel, public QgsF

enum Role
{
FeatureInfoRole = Qt::UserRole,
FeatureInfoRole = 0x1000, // Make sure no collisions with roles on QgsAttributeTableModel
FeatureRole
};

Expand Down Expand Up @@ -114,14 +114,30 @@ class GUI_EXPORT QgsFeatureListModel : public QSortFilterProxyModel, public QgsF
virtual QItemSelection mapSelectionFromMaster( const QItemSelection &selection ) const;
virtual QItemSelection mapSelectionToMaster( const QItemSelection &selection ) const;

QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const override;
QModelIndex parent( const QModelIndex &child ) const override;
int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;

QModelIndex fidToIndex( QgsFeatureId fid ) override;
QModelIndexList fidToIndexList( QgsFeatureId fid );

/**
* Sort this model by its display expression.
*
* \since QGIS 3.2
*/
bool sortByDisplayExpression() const;

/**
* Sort this model by its display expression.
*
* \note Not compatible with injectNull, if sorting by display expression is enabled,
* injectNull will automatically turned off.
*
* \since QGIS 3.2
*/
void setSortByDisplayExpression( bool sortByDisplayExpression );

public slots:
void onBeginRemoveRows( const QModelIndex &parent, int first, int last );
void onEndRemoveRows( const QModelIndex &parent, int first, int last );
Expand Down

0 comments on commit f1770c7

Please sign in to comment.