mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -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
|
:rtype: QgsFields
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
QgsCoordinateReferenceSystem crs() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the coordinate reference system for features retrieved from this source.
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
:rtype: QgsCoordinateReferenceSystem
|
||||||
|
%End
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
||||||
@ -138,6 +145,35 @@ Setup the simplification of geometries to fetch using the specified simplify met
|
|||||||
QgsVectorLayerFeatureIterator( const QgsVectorLayerFeatureIterator &rhs );
|
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 *
|
* This file has been generated automatically from *
|
||||||
* *
|
* *
|
||||||
|
@ -98,6 +98,11 @@ QgsFields QgsVectorLayerFeatureSource::fields() const
|
|||||||
return mFields;
|
return mFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsCoordinateReferenceSystem QgsVectorLayerFeatureSource::crs() const
|
||||||
|
{
|
||||||
|
return mCrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request )
|
QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request )
|
||||||
: QgsAbstractFeatureIteratorFromSource<QgsVectorLayerFeatureSource>( source, ownSource, request )
|
: QgsAbstractFeatureIteratorFromSource<QgsVectorLayerFeatureSource>( source, ownSource, request )
|
||||||
@ -1006,3 +1011,51 @@ bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureReques
|
|||||||
return true;
|
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 "qgsfeatureiterator.h"
|
||||||
#include "qgsfields.h"
|
#include "qgsfields.h"
|
||||||
#include "qgscoordinatereferencesystem.h"
|
#include "qgscoordinatereferencesystem.h"
|
||||||
|
#include "qgsfeaturesource.h"
|
||||||
|
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -67,6 +68,12 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource
|
|||||||
*/
|
*/
|
||||||
QgsFields fields() const;
|
QgsFields fields() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the coordinate reference system for features retrieved from this source.
|
||||||
|
* \since QGIS 3.0
|
||||||
|
*/
|
||||||
|
QgsCoordinateReferenceSystem crs() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
QgsAbstractFeatureSource *mProviderFeatureSource = nullptr;
|
QgsAbstractFeatureSource *mProviderFeatureSource = nullptr;
|
||||||
@ -253,4 +260,38 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
|
|||||||
bool checkGeometryValidity( const QgsFeature &feature );
|
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
|
#endif // QGSVECTORLAYERFEATUREITERATOR_H
|
||||||
|
@ -52,6 +52,7 @@ from qgis.core import (QgsWkbTypes,
|
|||||||
QgsSingleCategoryDiagramRenderer,
|
QgsSingleCategoryDiagramRenderer,
|
||||||
QgsDiagramLayerSettings,
|
QgsDiagramLayerSettings,
|
||||||
QgsTextFormat,
|
QgsTextFormat,
|
||||||
|
QgsVectorLayerSelectedFeatureSource,
|
||||||
NULL)
|
NULL)
|
||||||
from qgis.testing import start_app, unittest
|
from qgis.testing import start_app, unittest
|
||||||
from featuresourcetestbase import FeatureSourceTestCase
|
from featuresourcetestbase import FeatureSourceTestCase
|
||||||
@ -2298,6 +2299,71 @@ class TestQgsVectorLayer(unittest.TestCase, FeatureSourceTestCase):
|
|||||||
# compare xml documents
|
# compare xml documents
|
||||||
self.assertEqual(layer_doc.toString(), clone_doc.toString())
|
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:
|
# TODO:
|
||||||
# - fetch rect: feat with changed geometry: 1. in rect, 2. out of rect
|
# - fetch rect: feat with changed geometry: 1. in rect, 2. out of rect
|
||||||
|
Loading…
x
Reference in New Issue
Block a user