Skip to content

Commit

Permalink
Cleaner API for selecting features in QgsVectorLayer
Browse files Browse the repository at this point in the history
- add selectByRect( QgsRectangle&, SelectBehaviour) and
selectByIds( QgsFeatureIds, SelectBehaviour) for selecting
by rect and ids respectively, with options to add to selection/
remove from selection/intersect with current selection
- deprecate select( QgsRectangle ) and setSelectedFeatures in
favour of new methods
- add unit tests
  • Loading branch information
nyalldawson committed May 19, 2016
1 parent 1767d3b commit 23a3a77
Show file tree
Hide file tree
Showing 16 changed files with 188 additions and 55 deletions.
32 changes: 28 additions & 4 deletions python/core/qgsvectorlayer.sip
Expand Up @@ -304,19 +304,42 @@ class QgsVectorLayer : QgsMapLayer
*
* @see invertSelectionInRectangle(QgsRectangle & rect)
* @see selectByExpression()
* @deprecated use selectByRect() instead
*/
void select( QgsRectangle & rect, bool addToSelection );
void select( QgsRectangle & rect, bool addToSelection ) /Deprecated/;

/**
* Select features found within the search rectangle (in layer's coordinates)
* @param rect search rectangle
* @param behaviour selection type, allows adding to current selection, removing
* from selection, etc.
* @see invertSelectionInRectangle(QgsRectangle & rect)
* @see selectByExpression()
* @see selectByIds()
*/
void selectByRect( QgsRectangle & rect, SelectBehaviour behaviour = SetSelection );

/** Select matching features using an expression.
* @param expression expression to evaluate to select features
* @param behaviour selection type, allows adding to current selection, removing
* from selection, etc.
* @note added in QGIS 2.16
* @see select()
* @see modifySelection()
* @see selectByRect()
* @see selectByIds()
*/
void selectByExpression( const QString& expression, SelectBehaviour behaviour = SetSelection );

/** Select matching features using a list of feature IDs. Will emit the
* selectionChanged() signal with the clearAndSelect flag set.
* @param ids feature IDs to select
* @param behaviour selection type, allows adding to current selection, removing
* from selection, etc.
* @note added in QGIS 2.16
* @see selectByRect()
* @see selectByExpression()
*/
void selectByIds( const QgsFeatureIds &ids, SelectBehaviour behaviour = SetSelection );

/**
* Modifies the current selection on this layer
*
Expand Down Expand Up @@ -386,8 +409,9 @@ class QgsVectorLayer : QgsMapLayer
* clearAndSelect flag set.
*
* @param ids The ids which will be the new selection
* @deprecated use selectByIds() instead
*/
void setSelectedFeatures( const QgsFeatureIds &ids );
void setSelectedFeatures( const QgsFeatureIds &ids ) /Deprecated/;

/** Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,0,0,0) is returned */
QgsRectangle boundingBoxOfSelected();
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsmaptoolselectutils.cpp
Expand Up @@ -221,7 +221,7 @@ void QgsMapToolSelectUtils::setSelectFeatures( QgsMapCanvas* canvas,
}
else
{
vlayer->setSelectedFeatures( newSelectedFeatures );
vlayer->selectByIds( newSelectedFeatures );
}

QApplication::restoreOverrideCursor();
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsmergeattributesdialog.cpp
Expand Up @@ -459,7 +459,7 @@ void QgsMergeAttributesDialog::on_mRemoveFeatureFromSelectionButton_clicked()
//remove feature from the vector layer selection
QgsFeatureIds selectedIds = mVectorLayer->selectedFeaturesIds();
selectedIds.remove( featureId );
mVectorLayer->setSelectedFeatures( selectedIds );
mVectorLayer->selectByIds( selectedIds );
mMapCanvas->repaint();

//remove feature option from the combo box (without altering the current merge values)
Expand Down
83 changes: 52 additions & 31 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -437,32 +437,30 @@ void QgsVectorLayer::deselect( const QgsFeatureIds& featureIds )
}

void QgsVectorLayer::select( QgsRectangle & rect, bool addToSelection )
{
selectByRect( rect, addToSelection ? AddToSelection : SetSelection );
}

void QgsVectorLayer::selectByRect( QgsRectangle& rect, QgsVectorLayer::SelectBehaviour behaviour )
{
// normalize the rectangle
rect.normalize();

//select all the elements
QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
.setFilterRect( rect )
.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoGeometry )
.setSubsetOfAttributes( QgsAttributeList() ) );
QgsFeatureIds newSelection;

QgsFeatureIds ids;
QgsFeatureIterator features = getFeatures( QgsFeatureRequest()
.setFilterRect( rect )
.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoGeometry )
.setSubsetOfAttributes( QgsAttributeList() ) );

QgsFeature f;
while ( fit.nextFeature( f ) )
QgsFeature feat;
while ( features.nextFeature( feat ) )
{
ids << f.id();
newSelection << feat.id();
}
features.close();

if ( !addToSelection )
{
setSelectedFeatures( mSelectedFeatureIds + ids );
}
else
{
select( ids );
}
selectByIds( newSelection, behaviour );
}

void QgsVectorLayer::selectByExpression( const QString& expression, QgsVectorLayer::SelectBehaviour behaviour )
Expand All @@ -478,10 +476,8 @@ void QgsVectorLayer::selectByExpression( const QString& expression, QgsVectorLay
{
QgsFeatureRequest request = QgsFeatureRequest().setFilterExpression( expression )
.setExpressionContext( context )
.setFlags( QgsFeatureRequest::NoGeometry );
//TODO - investigate whether removing all attributes is possible
//for now, just set the first attribute
request.setSubsetOfAttributes( QgsAttributeList() << 0 );
.setFlags( QgsFeatureRequest::NoGeometry )
.setSubsetOfAttributes( QgsAttributeList() );

QgsFeatureIterator features = getFeatures( request );

Expand Down Expand Up @@ -527,7 +523,36 @@ void QgsVectorLayer::selectByExpression( const QString& expression, QgsVectorLay
}
}

setSelectedFeatures( newSelection );
selectByIds( newSelection );
}

void QgsVectorLayer::selectByIds( const QgsFeatureIds& ids, QgsVectorLayer::SelectBehaviour behaviour )
{
QgsFeatureIds newSelection;

switch ( behaviour )
{
case SetSelection:
newSelection = ids;
break;

case AddToSelection:
newSelection = mSelectedFeatureIds + ids;
break;

case RemoveFromSelection:
newSelection = mSelectedFeatureIds - ids;
break;

case IntersectSelection:
newSelection = mSelectedFeatureIds.intersect( ids );
break;
}

QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - newSelection;
mSelectedFeatureIds = newSelection;

emit selectionChanged( newSelection, deselectedFeatures, true );
}

void QgsVectorLayer::modifySelection( QgsFeatureIds selectIds, QgsFeatureIds deselectIds )
Expand All @@ -548,12 +573,12 @@ void QgsVectorLayer::invertSelection()
{
QgsFeatureIds ids = allFeatureIds();
ids.subtract( mSelectedFeatureIds );
setSelectedFeatures( ids );
selectByIds( ids );
}

void QgsVectorLayer::selectAll()
{
setSelectedFeatures( allFeatureIds() );
selectByIds( allFeatureIds() );
}

QgsFeatureIds QgsVectorLayer::allFeatureIds()
Expand Down Expand Up @@ -607,7 +632,7 @@ void QgsVectorLayer::removeSelection()
if ( mSelectedFeatureIds.isEmpty() )
return;

setSelectedFeatures( QgsFeatureIds() );
selectByIds( QgsFeatureIds() );
}

QgsVectorDataProvider* QgsVectorLayer::dataProvider()
Expand Down Expand Up @@ -2555,11 +2580,7 @@ bool QgsVectorLayer::rollBack( bool deleteBuffer )

void QgsVectorLayer::setSelectedFeatures( const QgsFeatureIds& ids )
{
QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - ids;

mSelectedFeatureIds = ids;

emit selectionChanged( ids, deselectedFeatures, true );
selectByIds( ids, SetSelection );
}

int QgsVectorLayer::selectedFeatureCount()
Expand Down Expand Up @@ -2630,7 +2651,7 @@ bool QgsVectorLayer::addFeatures( QgsFeatureList features, bool makeSelected )
for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
ids << iter->id();

setSelectedFeatures( ids );
selectByIds( ids );
}

updateExtents();
Expand Down
32 changes: 28 additions & 4 deletions src/core/qgsvectorlayer.h
Expand Up @@ -667,19 +667,42 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*
* @see invertSelectionInRectangle(QgsRectangle & rect)
* @see selectByExpression()
* @deprecated use selectByRect() instead
*/
void select( QgsRectangle & rect, bool addToSelection );
Q_DECL_DEPRECATED void select( QgsRectangle & rect, bool addToSelection );

/**
* Select features found within the search rectangle (in layer's coordinates)
* @param rect search rectangle
* @param behaviour selection type, allows adding to current selection, removing
* from selection, etc.
* @see invertSelectionInRectangle(QgsRectangle & rect)
* @see selectByExpression()
* @see selectByIds()
*/
void selectByRect( QgsRectangle & rect, SelectBehaviour behaviour = SetSelection );

/** Select matching features using an expression.
* @param expression expression to evaluate to select features
* @param behaviour selection type, allows adding to current selection, removing
* from selection, etc.
* @note added in QGIS 2.16
* @see select()
* @see modifySelection()
* @see selectByRect()
* @see selectByIds()
*/
void selectByExpression( const QString& expression, SelectBehaviour behaviour = SetSelection );

/** Select matching features using a list of feature IDs. Will emit the
* selectionChanged() signal with the clearAndSelect flag set.
* @param ids feature IDs to select
* @param behaviour selection type, allows adding to current selection, removing
* from selection, etc.
* @note added in QGIS 2.16
* @see selectByRect()
* @see selectByExpression()
*/
void selectByIds( const QgsFeatureIds &ids, SelectBehaviour behaviour = SetSelection );

/**
* Modifies the current selection on this layer
*
Expand Down Expand Up @@ -749,8 +772,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
* clearAndSelect flag set.
*
* @param ids The ids which will be the new selection
* @deprecated use selectByIds() instead
*/
void setSelectedFeatures( const QgsFeatureIds &ids );
Q_DECL_DEPRECATED void setSelectedFeatures( const QgsFeatureIds &ids );

/** Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,0,0,0) is returned */
QgsRectangle boundingBoxOfSelected();
Expand Down
2 changes: 1 addition & 1 deletion src/gui/attributetable/qgsvectorlayerselectionmanager.cpp
Expand Up @@ -41,7 +41,7 @@ void QgsVectorLayerSelectionManager::deselect( const QgsFeatureIds& ids )

void QgsVectorLayerSelectionManager::setSelectedFeatures( const QgsFeatureIds& ids )
{
mLayer->setSelectedFeatures( ids );
mLayer->selectByIds( ids );
}

const QgsFeatureIds& QgsVectorLayerSelectionManager::selectedFeaturesIds() const
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/evis/idtool/eviseventidtool.cpp
Expand Up @@ -117,7 +117,7 @@ void eVisEventIdTool::select( const QgsPoint& thePoint )
newSelectedFeatures.insert( f.id() );
}

myLayer->setSelectedFeatures( newSelectedFeatures );
myLayer->selectByIds( newSelectedFeatures );

//Launch a new event browser to view selected features
mBrowser = new eVisGenericEventBrowserGui( mCanvas, mCanvas, nullptr );
Expand Down
Expand Up @@ -251,7 +251,7 @@ void QgsGeometryCheckerSetupTab::runChecks()
newlayer->dataProvider()->addFeatures( features );

// Set selected features
newlayer->setSelectedFeatures( selectedFeatures );
newlayer->selectByIds( selectedFeatures );
}
layer = newlayer;
}
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/geometry_checker/utils/qgsfeaturepool.cpp
Expand Up @@ -86,7 +86,7 @@ void QgsFeaturePool::addFeature( QgsFeature& feature )
{
QgsFeatureIds selectedFeatureIds = mLayer->selectedFeaturesIds();
selectedFeatureIds.insert( feature.id() );
mLayer->setSelectedFeatures( selectedFeatureIds );
mLayer->selectByIds( selectedFeatureIds );
}
mLayerMutex.unlock();
mIndexMutex.lock();
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/geometry_snapper/qgsgeometrysnapperdialog.cpp
Expand Up @@ -249,7 +249,7 @@ void QgsGeometrySnapperDialog::run()
newlayer->dataProvider()->addFeatures( features );

// Set selected features
newlayer->setSelectedFeatures( selectedFeatures );
newlayer->selectByIds( selectedFeatures );
}
layer = newlayer;
}
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/spatialquery/qgsspatialquerydialog.cpp
Expand Up @@ -238,13 +238,13 @@ void QgsSpatialQueryDialog::showResultQuery( QDateTime *datetimeStart, QDateTime
switch ( typeResultFor )
{
case selectedNew:
mLayerTarget->setSelectedFeatures( mFeatureResult );
mLayerTarget->selectByIds( mFeatureResult );
break;
case selectedAdd:
mLayerTarget->setSelectedFeatures( mLayerTarget->selectedFeaturesIds() + mFeatureResult );
mLayerTarget->selectByIds( mLayerTarget->selectedFeaturesIds() + mFeatureResult );
break;
case selectedRemove:
mLayerTarget->setSelectedFeatures( mLayerTarget->selectedFeaturesIds() - mFeatureResult );
mLayerTarget->selectByIds( mLayerTarget->selectedFeaturesIds() - mFeatureResult );
break;
default:
return;
Expand Down
2 changes: 1 addition & 1 deletion src/server/qgswfsserver.cpp
Expand Up @@ -1673,7 +1673,7 @@ QDomDocument QgsWFSServer::transaction( const QString& requestBody )
}
#endif

layer->setSelectedFeatures( fids );
layer->selectByIds( fids );
layer->deleteSelectedFeatures();
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/server/qgswmsserver.cpp
Expand Up @@ -2802,7 +2802,7 @@ QStringList QgsWMSServer::applyFeatureSelections( const QStringList& layerList )
selectedIds.insert( STRING_TO_FID( id ) );
}

vLayer->setSelectedFeatures( selectedIds );
vLayer->selectByIds( selectedIds );
}


Expand All @@ -2819,7 +2819,7 @@ void QgsWMSServer::clearFeatureSelections( const QStringList& layerIds ) const
if ( !layer )
continue;

layer->setSelectedFeatures( QgsFeatureIds() );
layer->selectByIds( QgsFeatureIds() );
}

return;
Expand Down
2 changes: 1 addition & 1 deletion tests/src/core/testqgsvectorlayer.cpp
Expand Up @@ -222,7 +222,7 @@ void TestQgsVectorLayer::QgsVectorLayerGetValues()
//make a selection
QgsFeatureIds ids;
ids << f2.id() << f3.id();
layer->setSelectedFeatures( ids );
layer->selectByIds( ids );

bool ok;
QList<QVariant> varList = layer->getValues( "col1", ok );
Expand Down
2 changes: 1 addition & 1 deletion tests/src/gui/testqgsdualview.cpp
Expand Up @@ -137,7 +137,7 @@ void TestQgsDualView::testSelectAll()
mDualView->mTableView->selectAll();
QVERIFY( mPointsLayer->selectedFeatureCount() == 10 );

mPointsLayer->setSelectedFeatures( QgsFeatureIds() );
mPointsLayer->selectByIds( QgsFeatureIds() );
mCanvas->setExtent( QgsRectangle( -110, 40, -100, 48 ) );
mDualView->mTableView->selectAll();
QVERIFY( mPointsLayer->selectedFeatureCount() == 1 );
Expand Down

0 comments on commit 23a3a77

Please sign in to comment.