1 /***************************************************************************
2 qgsfeaturesource.cpp
3 -------------------
4 begin : May 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "qgsfeaturesource.h"
19 #include "qgsfeaturerequest.h"
20 #include "qgsfeatureiterator.h"
21 #include "qgsmemoryproviderutils.h"
22 #include "qgsfeedback.h"
23 #include "qgsvectorlayer.h"
24 #include "qgsvectordataprovider.h"
25
hasFeatures() const26 QgsFeatureSource::FeatureAvailability QgsFeatureSource::hasFeatures() const
27 {
28 return FeaturesMaybeAvailable;
29 }
30
uniqueValues(int fieldIndex,int limit) const31 QSet<QVariant> QgsFeatureSource::uniqueValues( int fieldIndex, int limit ) const
32 {
33 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
34 return QSet<QVariant>();
35
36 QgsFeatureRequest req;
37 req.setFlags( QgsFeatureRequest::NoGeometry );
38 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
39
40 QSet<QVariant> values;
41 QgsFeatureIterator it = getFeatures( req );
42 QgsFeature f;
43 while ( it.nextFeature( f ) )
44 {
45 values.insert( f.attribute( fieldIndex ) );
46 if ( limit > 0 && values.size() >= limit )
47 return values;
48 }
49 return values;
50 }
51
minimumValue(int fieldIndex) const52 QVariant QgsFeatureSource::minimumValue( int fieldIndex ) const
53 {
54 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
55 return QVariant();
56
57 QgsFeatureRequest req;
58 req.setFlags( QgsFeatureRequest::NoGeometry );
59 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
60
61 QVariant min;
62 QgsFeatureIterator it = getFeatures( req );
63 QgsFeature f;
64 while ( it.nextFeature( f ) )
65 {
66 const QVariant v = f.attribute( fieldIndex );
67 if ( !v.isNull() && ( qgsVariantLessThan( v, min ) || min.isNull() ) )
68 {
69 min = v;
70 }
71 }
72 return min;
73 }
74
maximumValue(int fieldIndex) const75 QVariant QgsFeatureSource::maximumValue( int fieldIndex ) const
76 {
77 if ( fieldIndex < 0 || fieldIndex >= fields().count() )
78 return QVariant();
79
80 QgsFeatureRequest req;
81 req.setFlags( QgsFeatureRequest::NoGeometry );
82 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
83
84 QVariant max;
85 QgsFeatureIterator it = getFeatures( req );
86 QgsFeature f;
87 while ( it.nextFeature( f ) )
88 {
89 const QVariant v = f.attribute( fieldIndex );
90 if ( !v.isNull() && ( qgsVariantGreaterThan( v, max ) || max.isNull() ) )
91 {
92 max = v;
93 }
94 }
95 return max;
96 }
97
sourceExtent() const98 QgsRectangle QgsFeatureSource::sourceExtent() const
99 {
100 QgsRectangle r;
101
102 QgsFeatureRequest req;
103 req.setNoAttributes();
104
105 QgsFeatureIterator it = getFeatures( req );
106 QgsFeature f;
107 while ( it.nextFeature( f ) )
108 {
109 if ( f.hasGeometry() )
110 r.combineExtentWith( f.geometry().boundingBox() );
111 }
112 return r;
113 }
114
allFeatureIds() const115 QgsFeatureIds QgsFeatureSource::allFeatureIds() const
116 {
117 QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
118 .setFlags( QgsFeatureRequest::NoGeometry )
119 .setNoAttributes() );
120
121 QgsFeatureIds ids;
122
123 QgsFeature fet;
124 while ( fit.nextFeature( fet ) )
125 {
126 ids << fet.id();
127 }
128
129 return ids;
130 }
131
materialize(const QgsFeatureRequest & request,QgsFeedback * feedback)132 QgsVectorLayer *QgsFeatureSource::materialize( const QgsFeatureRequest &request, QgsFeedback *feedback )
133 {
134 const QgsWkbTypes::Type outWkbType = ( request.flags() & QgsFeatureRequest::NoGeometry ) ? QgsWkbTypes::NoGeometry : wkbType();
135 const QgsCoordinateReferenceSystem crs = request.destinationCrs().isValid() ? request.destinationCrs() : sourceCrs();
136
137 const QgsAttributeList requestedAttrs = request.subsetOfAttributes();
138
139 QgsFields outFields;
140 if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes )
141 {
142 int i = 0;
143 const QgsFields sourceFields = fields();
144 for ( const QgsField &field : sourceFields )
145 {
146 if ( requestedAttrs.contains( i ) )
147 outFields.append( field );
148 i++;
149 }
150 }
151 else
152 {
153 outFields = fields();
154 }
155
156 std::unique_ptr< QgsVectorLayer > layer( QgsMemoryProviderUtils::createMemoryLayer(
157 sourceName(),
158 outFields,
159 outWkbType,
160 crs ) );
161 QgsFeature f;
162 QgsFeatureIterator it = getFeatures( request );
163 const int fieldCount = fields().count();
164 while ( it.nextFeature( f ) )
165 {
166 if ( feedback && feedback->isCanceled() )
167 break;
168
169 if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes )
170 {
171 // remove unused attributes
172 QgsAttributes attrs;
173 for ( int i = 0; i < fieldCount; ++i )
174 {
175 if ( requestedAttrs.contains( i ) )
176 {
177 attrs.append( f.attributes().at( i ) );
178 }
179 }
180
181 f.setAttributes( attrs );
182 }
183
184 layer->dataProvider()->addFeature( f, QgsFeatureSink::FastInsert );
185 }
186
187 return layer.release();
188 }
189
hasSpatialIndex() const190 QgsFeatureSource::SpatialIndexPresence QgsFeatureSource::hasSpatialIndex() const
191 {
192 return SpatialIndexUnknown;
193 }
194
195