Skip to content
Permalink
Browse files

Update currently edited feature in attribute table when selection cha…

…nges

It's a very common pitfall for people to toggle the selection instead of
the edit selection in the form view of the attribute table. I've noticed
clicking people repeatedly on the list because they know it's not
reliably going to give them what they want.

This change updates the active feature in the form view on a selection
change if one of the selected entries is visible in the current filter.
  • Loading branch information
m-kuhn committed May 17, 2018
1 parent 2f0fbc6 commit 53324bf13c93d15d5e8d708a3bd0d8e3ab21c6f0
Showing with 89 additions and 12 deletions.
  1. +85 −11 src/gui/attributetable/qgsfeaturelistview.cpp
  2. +4 −1 src/gui/attributetable/qgsfeaturelistview.h
@@ -58,6 +58,10 @@ void QgsFeatureListView::setModel( QgsFeatureListModel *featureListModel )

mFeatureSelectionModel = new QgsFeatureSelectionModel( featureListModel, featureListModel, mFeatureSelectionManager, this );
setSelectionModel( mFeatureSelectionModel );
connect( featureListModel->layerCache()->layer(), &QgsVectorLayer::selectionChanged, this, [ this ]()
{
ensureEditSelection( true );
} );

if ( mItemDelegate && mItemDelegate->parent() == this )
{
@@ -75,9 +79,9 @@ void QgsFeatureListView::setModel( QgsFeatureListModel *featureListModel )
this, static_cast<void ( QgsFeatureListView::* )()>( &QgsFeatureListView::repaintRequested ) );
connect( mCurrentEditSelectionModel, &QItemSelectionModel::selectionChanged, this, &QgsFeatureListView::editSelectionChanged );
connect( mModel->layerCache()->layer(), &QgsVectorLayer::attributeValueChanged, this, [ = ] { repaintRequested(); } );
connect( featureListModel, &QgsFeatureListModel::rowsRemoved, this, &QgsFeatureListView::ensureEditSelection );
connect( featureListModel, &QgsFeatureListModel::rowsInserted, this, &QgsFeatureListView::ensureEditSelection );
connect( featureListModel, &QgsFeatureListModel::modelReset, this, &QgsFeatureListView::ensureEditSelection );
connect( featureListModel, &QgsFeatureListModel::rowsRemoved, this, [ this ]() { ensureEditSelection(); } );
connect( featureListModel, &QgsFeatureListModel::rowsInserted, this, [ this ]() { ensureEditSelection(); } );
connect( featureListModel, &QgsFeatureListModel::modelReset, this, [ this ]() { ensureEditSelection(); } );
}

bool QgsFeatureListView::setDisplayExpression( const QString &expression )
@@ -334,17 +338,87 @@ void QgsFeatureListView::selectRow( const QModelIndex &index, bool anchor )
mFeatureSelectionModel->selectFeatures( QItemSelection( tl, br ), command );
}

void QgsFeatureListView::ensureEditSelection()
void QgsFeatureListView::ensureEditSelection( bool inSelection )
{
QModelIndexList selectedIndexes = mCurrentEditSelectionModel->selectedIndexes();
// If there is no selection or an invalid selection (and there would be something we could select) : select it
if ( ( selectedIndexes.isEmpty()
|| mModel->mapFromMaster( selectedIndexes.first() ).row() == -1 )
&& mModel->rowCount() )
if ( !mModel->rowCount() )
return;

const QModelIndexList selectedIndexes = mCurrentEditSelectionModel->selectedIndexes();

// We potentially want a new edit selection
// If we it should be in the feature selection
// but we don't find a matching one we might
// still stick to the old edit selection
bool editSelectionUpdateRequested = false;
// There is a valid selection available which we
// could fall back to
bool validEditSelectionAvailable = false;

if ( selectedIndexes.isEmpty() || mModel->mapFromMaster( selectedIndexes.first() ).row() == -1 )
{
validEditSelectionAvailable = false;
}
else
{
validEditSelectionAvailable = true;
}

// If we want to force the edit selection to be within the feature selection
// let's do some additional checks
if ( inSelection )
{
// no valid edit selection, update anyway
if ( !validEditSelectionAvailable )
{
editSelectionUpdateRequested = true;
}
else
{
// valid selection: update only if it's not in the feature selection
const QgsFeatureIds selectedFids = layerCache()->layer()->selectedFeatureIds();

if ( !selectedFids.contains( mModel->idxToFid( mModel->mapFromMaster( selectedIndexes.first() ) ) ) )
{
editSelectionUpdateRequested = true;
}
}
}
else
{
// we don't care if the edit selection is in the feature selection?
// well then, only update if there is no valid edit selection availble
if ( !validEditSelectionAvailable )
editSelectionUpdateRequested = true;
}

if ( editSelectionUpdateRequested )
{
QTimer::singleShot( 0, this, [ this ]()
QTimer::singleShot( 0, this, [ this, inSelection, validEditSelectionAvailable ]()
{
setEditSelection( mModel->mapToMaster( mModel->index( 0, 0 ) ), QItemSelectionModel::ClearAndSelect );
int rowToSelect = -1;

if ( inSelection )
{
const QgsFeatureIds selectedFids = layerCache()->layer()->selectedFeatureIds();
const int rowCount = mModel->rowCount();

for ( int i = 0; i < rowCount; i++ )
{
if ( selectedFids.contains( mModel->idxToFid( mModel->index( i, 0 ) ) ) )
{
rowToSelect = i;
break;
}

if ( rowToSelect == -1 && !validEditSelectionAvailable )
rowToSelect = 0;
}
}
else
rowToSelect = 0;

if ( rowToSelect != -1 )
setEditSelection( mModel->mapToMaster( mModel->index( rowToSelect, 0 ) ), QItemSelectionModel::ClearAndSelect );
} );
}
}
@@ -184,8 +184,11 @@ class GUI_EXPORT QgsFeatureListView : public QListView

/**
* Make sure, there is an edit selection. If there is none, choose the first item.
* If \a inSelection is set to true, the edit selection is done in selected entries if
* there is a selected entry visible.
*
*/
void ensureEditSelection();
void ensureEditSelection( bool inSelection = false );

private:
void selectRow( const QModelIndex &index, bool anchor );

0 comments on commit 53324bf

Please sign in to comment.
You can’t perform that action at this time.