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     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     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   QgsWkbTypes::Type outWkbType = ( request.flags() & QgsFeatureRequest::NoGeometry ) ? QgsWkbTypes::NoGeometry : wkbType();
135   QgsCoordinateReferenceSystem crs = request.destinationCrs().isValid() ? request.destinationCrs() : sourceCrs();
136 
137   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   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