|
QGIS API Documentation
master-59fd5e0
|
00001 /*************************************************************************** 00002 qgsvectorlayercache.cpp 00003 Cache features of a vector layer 00004 ------------------- 00005 begin : January 2013 00006 copyright : (C) Matthias Kuhn 00007 email : matthias dot kuhn at gmx dot ch 00008 00009 *************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include "qgsvectorlayercache.h" 00019 #include "qgscacheindex.h" 00020 #include "qgscachedfeatureiterator.h" 00021 00022 QgsVectorLayerCache::QgsVectorLayerCache( QgsVectorLayer* layer, int cacheSize, QObject* parent ) 00023 : QObject( parent ) 00024 , mLayer( layer ) 00025 { 00026 mCache.setMaxCost( cacheSize ); 00027 00028 connect( mLayer, SIGNAL( featureDeleted( QgsFeatureId ) ), SLOT( featureDeleted( QgsFeatureId ) ) ); 00029 connect( mLayer, SIGNAL( featureAdded( QgsFeatureId ) ), SLOT( featureAdded( QgsFeatureId ) ) ); 00030 connect( mLayer, SIGNAL( layerDeleted() ), SLOT( layerDeleted() ) ); 00031 00032 setCacheGeometry( true ); 00033 setCacheSubsetOfAttributes( mLayer->pendingAllAttributesList() ); 00034 setCacheAddedAttributes( true ); 00035 00036 connect( mLayer, SIGNAL( attributeDeleted( int ) ), SLOT( attributeDeleted( int ) ) ); 00037 connect( mLayer, SIGNAL( updatedFields() ), SLOT( updatedFields() ) ); 00038 connect( mLayer, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ) ); 00039 } 00040 00041 void QgsVectorLayerCache::setCacheSize( int cacheSize ) 00042 { 00043 mCache.setMaxCost( cacheSize ); 00044 } 00045 00046 int QgsVectorLayerCache::cacheSize() 00047 { 00048 return mCache.maxCost(); 00049 } 00050 00051 void QgsVectorLayerCache::setCacheGeometry( bool cacheGeometry ) 00052 { 00053 mCacheGeometry = cacheGeometry && mLayer->hasGeometryType(); 00054 if ( cacheGeometry ) 00055 { 00056 connect( mLayer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), SLOT( geometryChanged( QgsFeatureId, QgsGeometry& ) ) ); 00057 } 00058 else 00059 { 00060 disconnect( mLayer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), this, SLOT( geometryChanged( QgsFeatureId, QgsGeometry& ) ) ); 00061 } 00062 } 00063 00064 void QgsVectorLayerCache::setCacheSubsetOfAttributes( const QgsAttributeList& attributes ) 00065 { 00066 mCachedAttributes = attributes; 00067 } 00068 00069 void QgsVectorLayerCache::setFullCache( bool fullCache ) 00070 { 00071 mFullCache = fullCache; 00072 00073 if ( mFullCache ) 00074 { 00075 // Add a little more than necessary... 00076 setCacheSize( mLayer->featureCount() + 100 ); 00077 00078 // Initialize the cache... 00079 QgsFeatureIterator it = getFeatures( QgsFeatureRequest() 00080 .setSubsetOfAttributes( mCachedAttributes ) 00081 .setFlags( !mCacheGeometry ? QgsFeatureRequest::NoGeometry : QgsFeatureRequest::Flags( 0 ) ) ); 00082 00083 int i = 0; 00084 00085 QTime t; 00086 t.start(); 00087 00088 QgsFeature f; 00089 while ( it.nextFeature( f ) ) 00090 { 00091 ++i; 00092 00093 if ( t.elapsed() > 1000 ) 00094 { 00095 bool cancel = false; 00096 emit progress( i, cancel ); 00097 if ( cancel ) 00098 break; 00099 00100 t.restart(); 00101 } 00102 } 00103 00104 it.close(); 00105 00106 emit finished(); 00107 } 00108 } 00109 00110 void QgsVectorLayerCache::addCacheIndex( QgsAbstractCacheIndex* cacheIndex ) 00111 { 00112 mCacheIndices.append( cacheIndex ); 00113 } 00114 00115 void QgsVectorLayerCache::setCacheAddedAttributes( bool cacheAddedAttributes ) 00116 { 00117 if ( cacheAddedAttributes ) 00118 { 00119 connect( mLayer, SIGNAL( attributeAdded( int ) ), SLOT( attributeAdded( int ) ) ); 00120 } 00121 else 00122 { 00123 disconnect( mLayer, SIGNAL( attributeAdded( int ) ), this, SLOT( attributeAdded( int ) ) ); 00124 } 00125 } 00126 00127 bool QgsVectorLayerCache::featureAtId( QgsFeatureId featureId, QgsFeature& feature, bool skipCache ) 00128 { 00129 bool featureFound = false; 00130 00131 QgsCachedFeature* cachedFeature = NULL; 00132 00133 if ( !skipCache ) 00134 { 00135 cachedFeature = mCache[ featureId ]; 00136 } 00137 00138 if ( cachedFeature != NULL ) 00139 { 00140 feature = QgsFeature( *cachedFeature->feature() ); 00141 featureFound = true; 00142 } 00143 else if ( mLayer->getFeatures( QgsFeatureRequest() 00144 .setFilterFid( featureId ) 00145 .setSubsetOfAttributes( mCachedAttributes ) 00146 .setFlags( !mCacheGeometry ? QgsFeatureRequest::NoGeometry : QgsFeatureRequest::Flags( 0 ) ) ) 00147 .nextFeature( feature ) ) 00148 { 00149 cacheFeature( feature ); 00150 featureFound = true; 00151 } 00152 00153 return featureFound; 00154 } 00155 00156 bool QgsVectorLayerCache::removeCachedFeature( QgsFeatureId fid ) 00157 { 00158 return mCache.remove( fid ); 00159 } 00160 00161 QgsVectorLayer* QgsVectorLayerCache::layer() 00162 { 00163 return mLayer; 00164 } 00165 00166 void QgsVectorLayerCache::requestCompleted( QgsFeatureRequest featureRequest, QgsFeatureIds fids ) 00167 { 00168 // If a request is too large for the cache don't notify to prevent from indexing incomplete requests 00169 if ( fids.count() < mCache.size() ) 00170 { 00171 foreach ( QgsAbstractCacheIndex* idx, mCacheIndices ) 00172 { 00173 idx->requestCompleted( featureRequest, fids ); 00174 } 00175 } 00176 } 00177 00178 void QgsVectorLayerCache::featureRemoved( QgsFeatureId fid ) 00179 { 00180 foreach ( QgsAbstractCacheIndex* idx, mCacheIndices ) 00181 { 00182 idx->flushFeature( fid ); 00183 } 00184 } 00185 00186 void QgsVectorLayerCache::attributeValueChanged( QgsFeatureId fid, int field, const QVariant& value ) 00187 { 00188 QgsCachedFeature* cachedFeat = mCache[ fid ]; 00189 00190 if ( NULL != cachedFeat ) 00191 { 00192 cachedFeat->mFeature->setAttribute( field, value ); 00193 } 00194 } 00195 00196 void QgsVectorLayerCache::featureDeleted( QgsFeatureId fid ) 00197 { 00198 mCache.remove( fid ); 00199 } 00200 00201 void QgsVectorLayerCache::featureAdded( QgsFeatureId fid ) 00202 { 00203 if ( mFullCache ) 00204 { 00205 if ( cacheSize() <= mLayer->featureCount() ) 00206 { 00207 setCacheSize( mLayer->featureCount() + 100 ); 00208 } 00209 00210 QgsFeature feat; 00211 featureAtId( fid, feat ); 00212 } 00213 } 00214 00215 void QgsVectorLayerCache::attributeAdded( int field ) 00216 { 00217 Q_UNUSED( field ) 00218 mCachedAttributes.append( field ); 00219 mCache.clear(); 00220 } 00221 00222 void QgsVectorLayerCache::attributeDeleted( int field ) 00223 { 00224 foreach ( QgsFeatureId fid, mCache.keys() ) 00225 { 00226 mCache[ fid ]->mFeature->deleteAttribute( field ); 00227 } 00228 } 00229 00230 void QgsVectorLayerCache::geometryChanged( QgsFeatureId fid, QgsGeometry& geom ) 00231 { 00232 QgsCachedFeature* cachedFeat = mCache[ fid ]; 00233 00234 if ( cachedFeat != NULL ) 00235 { 00236 cachedFeat->mFeature->setGeometry( geom ); 00237 } 00238 } 00239 00240 void QgsVectorLayerCache::layerDeleted() 00241 { 00242 emit cachedLayerDeleted(); 00243 mLayer = NULL; 00244 } 00245 00246 void QgsVectorLayerCache::updatedFields() 00247 { 00248 mCache.clear(); 00249 } 00250 00251 QgsFeatureIterator QgsVectorLayerCache::getFeatures( const QgsFeatureRequest &featureRequest ) 00252 { 00253 QgsFeatureIterator it; 00254 bool requiresWriterIt = true; // If a not yet cached, but cachable request is made, this stays true. 00255 00256 if ( checkInformationCovered( featureRequest ) ) 00257 { 00258 // Check if an index is able to deliver the requested features 00259 foreach ( QgsAbstractCacheIndex *idx, mCacheIndices ) 00260 { 00261 if ( idx->getCacheIterator( it, featureRequest ) ) 00262 { 00263 requiresWriterIt = false; 00264 break; 00265 } 00266 } 00267 } 00268 else 00269 { 00270 // Let the layer answer the request, so no caching of requests 00271 // we don't want to cache is done 00272 requiresWriterIt = false; 00273 it = mLayer->getFeatures( featureRequest ); 00274 } 00275 00276 if ( requiresWriterIt && mLayer->dataProvider() ) 00277 { 00278 // No index was able to satisfy the request 00279 QgsFeatureRequest myRequest = QgsFeatureRequest( featureRequest ); 00280 00281 // Make sure if we cache the geometry, it gets fetched 00282 if ( mCacheGeometry && mLayer->hasGeometryType() ) 00283 myRequest.setFlags( featureRequest.flags() & ~QgsFeatureRequest::NoGeometry ); 00284 00285 // Make sure, all the cached attributes are requested as well 00286 QSet<int> attrs = featureRequest.subsetOfAttributes().toSet() + mCachedAttributes.toSet(); 00287 myRequest.setSubsetOfAttributes( attrs.toList() ); 00288 00289 it = QgsFeatureIterator( new QgsCachedFeatureWriterIterator( this, myRequest ) ); 00290 } 00291 00292 return it; 00293 } 00294 00295 bool QgsVectorLayerCache::isFidCached( const QgsFeatureId fid ) 00296 { 00297 return mCache.contains( fid ); 00298 } 00299 00300 bool QgsVectorLayerCache::checkInformationCovered( const QgsFeatureRequest& featureRequest ) 00301 { 00302 QgsAttributeList requestedAttributes; 00303 00304 if ( !featureRequest.flags().testFlag( QgsFeatureRequest::SubsetOfAttributes ) ) 00305 { 00306 requestedAttributes = mLayer->pendingAllAttributesList(); 00307 } 00308 else 00309 { 00310 requestedAttributes = featureRequest.subsetOfAttributes(); 00311 } 00312 00313 // Check if we even cache the information requested 00314 foreach ( int attr, requestedAttributes ) 00315 { 00316 if ( !mCachedAttributes.contains( attr ) ) 00317 { 00318 return false; 00319 } 00320 } 00321 00322 // If the request needs geometry but we don't cache this... 00323 if ( !featureRequest.flags().testFlag( QgsFeatureRequest::NoGeometry ) 00324 && !mCacheGeometry ) 00325 { 00326 return false; 00327 } 00328 00329 return true; 00330 }