mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #4679 from nyalldawson/selected_feature_source
QgsVectorLayerSelectedFeatureSource
This commit is contained in:
commit
63083abefe
@ -46,6 +46,13 @@ class QgsVectorLayerFeatureSource : QgsAbstractFeatureSource
|
||||
:rtype: QgsFields
|
||||
%End
|
||||
|
||||
QgsCoordinateReferenceSystem crs() const;
|
||||
%Docstring
|
||||
Returns the coordinate reference system for features retrieved from this source.
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsCoordinateReferenceSystem
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@ -138,6 +145,35 @@ Setup the simplification of geometries to fetch using the specified simplify met
|
||||
QgsVectorLayerFeatureIterator( const QgsVectorLayerFeatureIterator &rhs );
|
||||
};
|
||||
|
||||
|
||||
|
||||
class QgsVectorLayerSelectedFeatureSource : QgsFeatureSource
|
||||
{
|
||||
%Docstring
|
||||
QgsFeatureSource subclass for the selected features from a QgsVectorLayer.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsvectorlayerfeatureiterator.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsVectorLayerSelectedFeatureSource( QgsVectorLayer *layer );
|
||||
%Docstring
|
||||
Constructor for QgsVectorLayerSelectedFeatureSource, for selected features from the specified ``layer``.
|
||||
The currently selected feature IDs are stored, so change to the layer selection after constructing
|
||||
the QgsVectorLayerSelectedFeatureSource will not be reflected.
|
||||
%End
|
||||
|
||||
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) const;
|
||||
virtual QgsCoordinateReferenceSystem sourceCrs() const;
|
||||
virtual QgsFields fields() const;
|
||||
virtual QgsWkbTypes::Type wkbType() const;
|
||||
virtual long featureCount() const;
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
|
@ -98,6 +98,11 @@ QgsFields QgsVectorLayerFeatureSource::fields() const
|
||||
return mFields;
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsVectorLayerFeatureSource::crs() const
|
||||
{
|
||||
return mCrs;
|
||||
}
|
||||
|
||||
|
||||
QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request )
|
||||
: QgsAbstractFeatureIteratorFromSource<QgsVectorLayerFeatureSource>( source, ownSource, request )
|
||||
@ -1006,3 +1011,51 @@ bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureReques
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsVectorLayerSelectedFeatureSource
|
||||
//
|
||||
|
||||
QgsVectorLayerSelectedFeatureSource::QgsVectorLayerSelectedFeatureSource( QgsVectorLayer *layer )
|
||||
: mSource( layer )
|
||||
, mSelectedFeatureIds( layer->selectedFeatureIds() )
|
||||
, mWkbType( layer->wkbType() )
|
||||
{}
|
||||
|
||||
QgsFeatureIterator QgsVectorLayerSelectedFeatureSource::getFeatures( const QgsFeatureRequest &request ) const
|
||||
{
|
||||
QgsFeatureRequest req( request );
|
||||
|
||||
if ( req.filterFids().isEmpty() && req.filterType() != QgsFeatureRequest::FilterFid )
|
||||
{
|
||||
req.setFilterFids( mSelectedFeatureIds );
|
||||
}
|
||||
else if ( !req.filterFids().isEmpty() )
|
||||
{
|
||||
QgsFeatureIds reqIds = mSelectedFeatureIds;
|
||||
reqIds.intersect( req.filterFids() );
|
||||
req.setFilterFids( reqIds );
|
||||
}
|
||||
|
||||
return mSource.getFeatures( req );
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsVectorLayerSelectedFeatureSource::sourceCrs() const
|
||||
{
|
||||
return mSource.crs();
|
||||
}
|
||||
|
||||
QgsFields QgsVectorLayerSelectedFeatureSource::fields() const
|
||||
{
|
||||
return mSource.fields();
|
||||
}
|
||||
|
||||
QgsWkbTypes::Type QgsVectorLayerSelectedFeatureSource::wkbType() const
|
||||
{
|
||||
return mWkbType;
|
||||
}
|
||||
|
||||
long QgsVectorLayerSelectedFeatureSource::featureCount() const
|
||||
{
|
||||
return mSelectedFeatureIds.count();
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "qgsfeatureiterator.h"
|
||||
#include "qgsfields.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsfeaturesource.h"
|
||||
|
||||
#include <QSet>
|
||||
#include <memory>
|
||||
@ -67,6 +68,12 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource
|
||||
*/
|
||||
QgsFields fields() const;
|
||||
|
||||
/**
|
||||
* Returns the coordinate reference system for features retrieved from this source.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsCoordinateReferenceSystem crs() const;
|
||||
|
||||
protected:
|
||||
|
||||
QgsAbstractFeatureSource *mProviderFeatureSource = nullptr;
|
||||
@ -253,4 +260,38 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
|
||||
bool checkGeometryValidity( const QgsFeature &feature );
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \class QgsVectorLayerSelectedFeatureSource
|
||||
* \ingroup core
|
||||
* QgsFeatureSource subclass for the selected features from a QgsVectorLayer.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsVectorLayerSelectedFeatureSource : public QgsFeatureSource
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsVectorLayerSelectedFeatureSource, for selected features from the specified \a layer.
|
||||
* The currently selected feature IDs are stored, so change to the layer selection after constructing
|
||||
* the QgsVectorLayerSelectedFeatureSource will not be reflected.
|
||||
*/
|
||||
QgsVectorLayerSelectedFeatureSource( QgsVectorLayer *layer );
|
||||
|
||||
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) const override;
|
||||
virtual QgsCoordinateReferenceSystem sourceCrs() const override;
|
||||
virtual QgsFields fields() const override;
|
||||
virtual QgsWkbTypes::Type wkbType() const override;
|
||||
virtual long featureCount() const override;
|
||||
|
||||
private:
|
||||
|
||||
// ideally this wouldn't be mutable, but QgsVectorLayerFeatureSource has non-const getFeatures()
|
||||
mutable QgsVectorLayerFeatureSource mSource;
|
||||
QgsFeatureIds mSelectedFeatureIds;
|
||||
QgsWkbTypes::Type mWkbType = QgsWkbTypes::Unknown;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSVECTORLAYERFEATUREITERATOR_H
|
||||
|
@ -52,6 +52,7 @@ from qgis.core import (QgsWkbTypes,
|
||||
QgsSingleCategoryDiagramRenderer,
|
||||
QgsDiagramLayerSettings,
|
||||
QgsTextFormat,
|
||||
QgsVectorLayerSelectedFeatureSource,
|
||||
NULL)
|
||||
from qgis.testing import start_app, unittest
|
||||
from featuresourcetestbase import FeatureSourceTestCase
|
||||
@ -2298,6 +2299,71 @@ class TestQgsVectorLayer(unittest.TestCase, FeatureSourceTestCase):
|
||||
# compare xml documents
|
||||
self.assertEqual(layer_doc.toString(), clone_doc.toString())
|
||||
|
||||
def testQgsVectorLayerSelectedFeatureSource(self):
|
||||
"""
|
||||
test QgsVectorLayerSelectedFeatureSource
|
||||
"""
|
||||
|
||||
layer = QgsVectorLayer("Point?crs=epsg:3111&field=fldtxt:string&field=fldint:integer",
|
||||
"addfeat", "memory")
|
||||
pr = layer.dataProvider()
|
||||
f1 = QgsFeature(1)
|
||||
f1.setAttributes(["test", 123])
|
||||
f1.setGeometry(QgsGeometry.fromPoint(QgsPointXY(100, 200)))
|
||||
f2 = QgsFeature(2)
|
||||
f2.setAttributes(["test2", 457])
|
||||
f2.setGeometry(QgsGeometry.fromPoint(QgsPointXY(200, 200)))
|
||||
f3 = QgsFeature(3)
|
||||
f3.setAttributes(["test2", 888])
|
||||
f3.setGeometry(QgsGeometry.fromPoint(QgsPointXY(300, 200)))
|
||||
f4 = QgsFeature(4)
|
||||
f4.setAttributes(["test3", -1])
|
||||
f4.setGeometry(QgsGeometry.fromPoint(QgsPointXY(400, 300)))
|
||||
f5 = QgsFeature(5)
|
||||
f5.setAttributes(["test4", 0])
|
||||
f5.setGeometry(QgsGeometry.fromPoint(QgsPointXY(0, 0)))
|
||||
self.assertTrue(pr.addFeatures([f1, f2, f3, f4, f5]))
|
||||
self.assertEqual(layer.featureCount(), 5)
|
||||
|
||||
source = QgsVectorLayerSelectedFeatureSource(layer)
|
||||
self.assertEqual(source.sourceCrs().authid(), 'EPSG:3111')
|
||||
self.assertEqual(source.wkbType(), QgsWkbTypes.Point)
|
||||
self.assertEqual(source.fields(), layer.fields())
|
||||
|
||||
# no selection
|
||||
self.assertEqual(source.featureCount(), 0)
|
||||
it = source.getFeatures()
|
||||
f = QgsFeature()
|
||||
self.assertFalse(it.nextFeature(f))
|
||||
|
||||
# with selection
|
||||
layer.selectByIds([f1.id(), f3.id(), f5.id()])
|
||||
source = QgsVectorLayerSelectedFeatureSource(layer)
|
||||
self.assertEqual(source.featureCount(), 3)
|
||||
ids = set([f.id() for f in source.getFeatures()])
|
||||
self.assertEqual(ids, {f1.id(), f3.id(), f5.id()})
|
||||
|
||||
# test that requesting subset of ids intersects this request with the selected ids
|
||||
ids = set([f.id() for f in source.getFeatures(QgsFeatureRequest().setFilterFids([f1.id(), f2.id(), f5.id()]))])
|
||||
self.assertEqual(ids, {f1.id(), f5.id()})
|
||||
|
||||
# test that requesting id works
|
||||
ids = set([f.id() for f in source.getFeatures(QgsFeatureRequest().setFilterFid(f1.id()))])
|
||||
self.assertEqual(ids, {f1.id()})
|
||||
ids = set([f.id() for f in source.getFeatures(QgsFeatureRequest().setFilterFid(f5.id()))])
|
||||
self.assertEqual(ids, {f5.id()})
|
||||
|
||||
# test that source has stored snapshot of selected features
|
||||
layer.selectByIds([f2.id(), f4.id()])
|
||||
self.assertEqual(source.featureCount(), 3)
|
||||
ids = set([f.id() for f in source.getFeatures()])
|
||||
self.assertEqual(ids, {f1.id(), f3.id(), f5.id()})
|
||||
|
||||
# test that source is not dependent on layer
|
||||
del layer
|
||||
ids = set([f.id() for f in source.getFeatures()])
|
||||
self.assertEqual(ids, {f1.id(), f3.id(), f5.id()})
|
||||
|
||||
|
||||
# TODO:
|
||||
# - fetch rect: feat with changed geometry: 1. in rect, 2. out of rect
|
||||
|
Loading…
x
Reference in New Issue
Block a user