Update currently edited feature in attribute table when selection changes

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.
This commit is contained in:
Matthias Kuhn 2018-05-17 14:26:41 +02:00
parent 2f0fbc6717
commit 53324bf13c
No known key found for this signature in database
GPG Key ID: A0E766808764D73F
2 changed files with 89 additions and 12 deletions

View File

@ -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 )
{
QTimer::singleShot( 0, this, [ this ]()
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 )
{
setEditSelection( mModel->mapToMaster( mModel->index( 0, 0 ) ), QItemSelectionModel::ClearAndSelect );
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, inSelection, validEditSelectionAvailable ]()
{
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 );
} );
}
}

View File

@ -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 );