Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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 53324bf
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 12 deletions.
96 changes: 85 additions & 11 deletions src/gui/attributetable/qgsfeaturelistview.cpp
Expand Up @@ -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 )
{
Expand All @@ -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 )
Expand Down Expand Up @@ -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 );
} );
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/gui/attributetable/qgsfeaturelistview.h
Expand Up @@ -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 );
Expand Down

0 comments on commit 53324bf

Please sign in to comment.