QGIS API Documentation  master-59fd5e0
src/core/qgsvectorlayercache.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines