QGIS API Documentation  2.0.1-Dufour
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsvectorlayercache.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayercache.cpp
3  Cache features of a vector layer
4  -------------------
5  begin : January 2013
6  copyright : (C) Matthias Kuhn
7  email : matthias dot kuhn at gmx dot ch
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 "qgsvectorlayercache.h"
19 #include "qgscacheindex.h"
21 
22 QgsVectorLayerCache::QgsVectorLayerCache( QgsVectorLayer* layer, int cacheSize, QObject* parent )
23  : QObject( parent )
24  , mLayer( layer )
25 {
26  mCache.setMaxCost( cacheSize );
27 
28  connect( mLayer, SIGNAL( featureDeleted( QgsFeatureId ) ), SLOT( featureDeleted( QgsFeatureId ) ) );
29  connect( mLayer, SIGNAL( featureAdded( QgsFeatureId ) ), SLOT( featureAdded( QgsFeatureId ) ) );
30  connect( mLayer, SIGNAL( layerDeleted() ), SLOT( layerDeleted() ) );
31 
32  setCacheGeometry( true );
35 
36  connect( mLayer, SIGNAL( attributeDeleted( int ) ), SLOT( attributeDeleted( int ) ) );
37  connect( mLayer, SIGNAL( updatedFields() ), SLOT( updatedFields() ) );
38  connect( mLayer, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), SLOT( onAttributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
39 }
40 
41 void QgsVectorLayerCache::setCacheSize( int cacheSize )
42 {
43  mCache.setMaxCost( cacheSize );
44 }
45 
47 {
48  return mCache.maxCost();
49 }
50 
51 void QgsVectorLayerCache::setCacheGeometry( bool cacheGeometry )
52 {
53  mCacheGeometry = cacheGeometry && mLayer->hasGeometryType();
54  if ( cacheGeometry )
55  {
57  }
58  else
59  {
60  disconnect( mLayer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), this, SLOT( geometryChanged( QgsFeatureId, QgsGeometry& ) ) );
61  }
62 }
63 
65 {
66  mCachedAttributes = attributes;
67 }
68 
69 void QgsVectorLayerCache::setFullCache( bool fullCache )
70 {
71  mFullCache = fullCache;
72 
73  if ( mFullCache )
74  {
75  // Add a little more than necessary...
76  setCacheSize( mLayer->featureCount() + 100 );
77 
78  // Initialize the cache...
80  .setSubsetOfAttributes( mCachedAttributes )
81  .setFlags( !mCacheGeometry ? QgsFeatureRequest::NoGeometry : QgsFeatureRequest::Flags( 0 ) ) );
82 
83  int i = 0;
84 
85  QTime t;
86  t.start();
87 
88  QgsFeature f;
89  while ( it.nextFeature( f ) )
90  {
91  ++i;
92 
93  if ( t.elapsed() > 1000 )
94  {
95  bool cancel = false;
96  emit progress( i, cancel );
97  if ( cancel )
98  break;
99 
100  t.restart();
101  }
102  }
103 
104  it.close();
105 
106  emit finished();
107  }
108 }
109 
111 {
112  mCacheIndices.append( cacheIndex );
113 }
114 
115 void QgsVectorLayerCache::setCacheAddedAttributes( bool cacheAddedAttributes )
116 {
117  if ( cacheAddedAttributes )
118  {
119  connect( mLayer, SIGNAL( attributeAdded( int ) ), SLOT( attributeAdded( int ) ) );
120  }
121  else
122  {
123  disconnect( mLayer, SIGNAL( attributeAdded( int ) ), this, SLOT( attributeAdded( int ) ) );
124  }
125 }
126 
127 bool QgsVectorLayerCache::featureAtId( QgsFeatureId featureId, QgsFeature& feature, bool skipCache )
128 {
129  bool featureFound = false;
130 
131  QgsCachedFeature* cachedFeature = NULL;
132 
133  if ( !skipCache )
134  {
135  cachedFeature = mCache[ featureId ];
136  }
137 
138  if ( cachedFeature != NULL )
139  {
140  feature = QgsFeature( *cachedFeature->feature() );
141  featureFound = true;
142  }
143  else if ( mLayer->getFeatures( QgsFeatureRequest()
144  .setFilterFid( featureId )
145  .setSubsetOfAttributes( mCachedAttributes )
146  .setFlags( !mCacheGeometry ? QgsFeatureRequest::NoGeometry : QgsFeatureRequest::Flags( 0 ) ) )
147  .nextFeature( feature ) )
148  {
149  cacheFeature( feature );
150  featureFound = true;
151  }
152 
153  return featureFound;
154 }
155 
157 {
158  return mCache.remove( fid );
159 }
160 
162 {
163  return mLayer;
164 }
165 
167 {
168  // If a request is too large for the cache don't notify to prevent from indexing incomplete requests
169  if ( fids.count() < mCache.size() )
170  {
171  foreach ( QgsAbstractCacheIndex* idx, mCacheIndices )
172  {
173  idx->requestCompleted( featureRequest, fids );
174  }
175  }
176 }
177 
179 {
180  foreach ( QgsAbstractCacheIndex* idx, mCacheIndices )
181  {
182  idx->flushFeature( fid );
183  }
184 }
185 
186 void QgsVectorLayerCache::onAttributeValueChanged( QgsFeatureId fid, int field, const QVariant& value )
187 {
188  QgsCachedFeature* cachedFeat = mCache[ fid ];
189 
190  if ( NULL != cachedFeat )
191  {
192  cachedFeat->mFeature->setAttribute( field, value );
193  }
194 
195  emit attributeValueChanged( fid, field, value );
196 }
197 
199 {
200  mCache.remove( fid );
201 }
202 
204 {
205  if ( mFullCache )
206  {
207  if ( cacheSize() <= mLayer->featureCount() )
208  {
209  setCacheSize( mLayer->featureCount() + 100 );
210  }
211 
212  QgsFeature feat;
213  featureAtId( fid, feat );
214  }
215 }
216 
218 {
219  Q_UNUSED( field )
220  mCachedAttributes.append( field );
221  mCache.clear();
222 }
223 
225 {
226  foreach ( QgsFeatureId fid, mCache.keys() )
227  {
228  mCache[ fid ]->mFeature->deleteAttribute( field );
229  }
230 }
231 
233 {
234  QgsCachedFeature* cachedFeat = mCache[ fid ];
235 
236  if ( cachedFeat != NULL )
237  {
238  cachedFeat->mFeature->setGeometry( geom );
239  }
240 }
241 
243 {
244  emit cachedLayerDeleted();
245  mLayer = NULL;
246 }
247 
249 {
250  mCache.clear();
251 }
252 
254 {
256  bool requiresWriterIt = true; // If a not yet cached, but cachable request is made, this stays true.
257 
258  if ( checkInformationCovered( featureRequest ) )
259  {
260  // Check if an index is able to deliver the requested features
261  foreach ( QgsAbstractCacheIndex *idx, mCacheIndices )
262  {
263  if ( idx->getCacheIterator( it, featureRequest ) )
264  {
265  requiresWriterIt = false;
266  break;
267  }
268  }
269  }
270  else
271  {
272  // Let the layer answer the request, so no caching of requests
273  // we don't want to cache is done
274  requiresWriterIt = false;
275  it = mLayer->getFeatures( featureRequest );
276  }
277 
278  if ( requiresWriterIt && mLayer->dataProvider() )
279  {
280  // No index was able to satisfy the request
281  QgsFeatureRequest myRequest = QgsFeatureRequest( featureRequest );
282 
283  // Make sure if we cache the geometry, it gets fetched
285  myRequest.setFlags( featureRequest.flags() & ~QgsFeatureRequest::NoGeometry );
286 
287  // Make sure, all the cached attributes are requested as well
288  QSet<int> attrs = featureRequest.subsetOfAttributes().toSet() + mCachedAttributes.toSet();
289  myRequest.setSubsetOfAttributes( attrs.toList() );
290 
291  it = QgsFeatureIterator( new QgsCachedFeatureWriterIterator( this, myRequest ) );
292  }
293 
294  return it;
295 }
296 
298 {
299  return mCache.contains( fid );
300 }
301 
303 {
304  QgsAttributeList requestedAttributes;
305 
306  if ( !featureRequest.flags().testFlag( QgsFeatureRequest::SubsetOfAttributes ) )
307  {
308  requestedAttributes = mLayer->pendingAllAttributesList();
309  }
310  else
311  {
312  requestedAttributes = featureRequest.subsetOfAttributes();
313  }
314 
315  // Check if we even cache the information requested
316  foreach ( int attr, requestedAttributes )
317  {
318  if ( !mCachedAttributes.contains( attr ) )
319  {
320  return false;
321  }
322  }
323 
324  // If the request needs geometry but we don't cache this...
325  if ( !featureRequest.flags().testFlag( QgsFeatureRequest::NoGeometry )
326  && !mCacheGeometry )
327  {
328  return false;
329  }
330 
331  return true;
332 }
Wrapper for iterator of features from vector data provider or vector layer.
friend class QgsCachedFeatureWriterIterator
const Flags & flags() const
QList< QgsAbstractCacheIndex * > mCacheIndices
QgsAttributeList mCachedAttributes
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:321
bool removeCachedFeature(QgsFeatureId fid)
Removes the feature identified by fid from the cache if present.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
bool isFidCached(const QgsFeatureId fid)
Check if a certain feature id is cached.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
const QgsAttributeList & subsetOfAttributes() const
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:72
bool setAttribute(int field, const QVariant &attr)
Set an attribute by id.
Definition: qgsfeature.cpp:191
QgsVectorLayer * layer()
Returns the layer to which this cache belongs.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:114
QCache< QgsFeatureId, QgsCachedFeature > mCache
void setCacheSubsetOfAttributes(const QgsAttributeList &attributes)
Set the subset of attributes to be cached.
void featureAdded(QgsFeatureId fid)
void attributeAdded(int field)
void setGeometry(const QgsGeometry &geom)
Set this feature's geometry from another QgsGeometry object (deep copy)
Definition: qgsfeature.cpp:135
void progress(int i, bool &cancel)
When filling the cache, this signal gets emitted periodically to notify about the progress and to be ...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest)
Query this VectorLayerCache for features.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
void featureDeleted(QgsFeatureId fid)
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
void cachedLayerDeleted()
Is emitted when the cached layer is deleted.
void geometryChanged(QgsFeatureId fid, QgsGeometry &geom)
bool checkInformationCovered(const QgsFeatureRequest &featureRequest)
Checks if the information required to complete the request is cached.
void attributeValueChanged(const QgsFeatureId &fid, const int &field, const QVariant &value)
Is emitted when an attribute is changed.
virtual bool getCacheIterator(QgsFeatureIterator &featureIterator, const QgsFeatureRequest &featureRequest)=0
Is called, when a feature request is issued on a cached layer.
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
virtual long featureCount() const
Number of features in the layer.
Abstract base class for cache indices.
Definition: qgscacheindex.h:29
QgsAttributeList pendingAllAttributesList()
returns list of attributes
QgsVectorLayer * mLayer
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
void setFullCache(bool fullCache)
This enables or disables full caching.
virtual void flushFeature(const QgsFeatureId fid)=0
Is called, whenever a feature is removed from the cache.
bool featureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id.
void cacheFeature(QgsFeature &feat)
void setCacheSize(int cacheSize)
Sets the maximum number of features to keep in the cache.
void requestCompleted(QgsFeatureRequest featureRequest, QgsFeatureIds fids)
Gets called, whenever the full list of feature ids for a certain request is known.
qint64 QgsFeatureId
Definition: qgsfeature.h:30
This is a wrapper class around a cached QgsFeature, which will inform the cache, when it has been del...
QgsVectorLayerCache(QgsVectorLayer *layer, int cacheSize, QObject *parent=NULL)
void featureRemoved(QgsFeatureId fid)
Gets called, whenever a feature has been removed.
int cacheSize()
Returns the maximum number of features this cache will hold.
void onAttributeValueChanged(QgsFeatureId fid, int field, const QVariant &value)
QgsVectorDataProvider * dataProvider()
Returns the data provider.
bool nextFeature(QgsFeature &f)
Do not fetch geometry.
void addCacheIndex(QgsAbstractCacheIndex *cacheIndex)
Adds a QgsAbstractCacheIndex to this cache.
Represents a vector layer which manages a vector based data sets.
QgsFeatureRequest & setFlags(Flags flags)
Set flags that affect how features will be fetched.
void finished()
When filling the cache, this signal gets emitted once the cache is fully initialized.
virtual void requestCompleted(QgsFeatureRequest featureRequest, QgsFeatureIds fids)
Implement this method to update the the indices, in case you need information contained by the reques...
void setCacheAddedAttributes(bool cacheAddedAttributes)
If this is enabled, the subset of cached attributes will automatically be extended to also include ne...
void attributeDeleted(int field)