QGIS API Documentation  master-59fd5e0
src/core/qgsvectorlayerfeatureiterator.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsvectorlayerfeatureiterator.cpp
00003     ---------------------
00004     begin                : Dezember 2012
00005     copyright            : (C) 2012 by Martin Dobias
00006     email                : wonder dot sk at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 #include "qgsvectorlayerfeatureiterator.h"
00016 
00017 #include "qgsmaplayerregistry.h"
00018 #include "qgsvectordataprovider.h"
00019 #include "qgsvectorlayer.h"
00020 #include "qgsvectorlayereditbuffer.h"
00021 #include "qgsvectorlayerjoinbuffer.h"
00022 
00023 QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayer* layer, const QgsFeatureRequest& request )
00024     : QgsAbstractFeatureIterator( request ), L( layer )
00025 {
00026 
00027   QgsVectorLayerJoinBuffer* joinBuffer = L->mJoinBuffer;
00028 
00029   // prepare joins: may add more attributes to fetch (in order to allow join)
00030   if ( joinBuffer->containsJoins() )
00031     prepareJoins();
00032 
00033   // by default provider's request is the same
00034   mProviderRequest = mRequest;
00035 
00036   if ( mProviderRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
00037   {
00038     // prepare list of attributes to match provider fields
00039     QgsAttributeList providerSubset;
00040     QgsAttributeList subset = mProviderRequest.subsetOfAttributes();
00041     const QgsFields &pendingFields = L->pendingFields();
00042     int nPendingFields = pendingFields.count();
00043     for ( int i = 0; i < subset.count(); ++i )
00044     {
00045       int attrIndex = subset[i];
00046       if ( attrIndex < 0 || attrIndex >= nPendingFields ) continue;
00047       if ( L->pendingFields().fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
00048         providerSubset << L->pendingFields().fieldOriginIndex( attrIndex );
00049     }
00050     mProviderRequest.setSubsetOfAttributes( providerSubset );
00051   }
00052 
00053   if ( request.filterType() == QgsFeatureRequest::FilterFid )
00054   {
00055     mFetchedFid = false;
00056   }
00057   else // no filter or filter by rect
00058   {
00059     mProviderIterator = L->dataProvider()->getFeatures( mProviderRequest );
00060 
00061     rewindEditBuffer();
00062   }
00063 }
00064 
00065 
00066 QgsVectorLayerFeatureIterator::~QgsVectorLayerFeatureIterator()
00067 {
00068   close();
00069 }
00070 
00071 
00072 
00073 bool QgsVectorLayerFeatureIterator::nextFeature( QgsFeature& f )
00074 {
00075   f.setValid( false );
00076 
00077   if ( mClosed )
00078     return false;
00079 
00080   if ( mRequest.filterType() == QgsFeatureRequest::FilterFid )
00081   {
00082     if ( mFetchedFid )
00083       return false;
00084     bool res = nextFeatureFid( f );
00085     mFetchedFid = true;
00086     return res;
00087   }
00088 
00089   QgsVectorLayerEditBuffer* editBuffer = L->editBuffer();
00090 
00091   if ( editBuffer )
00092   {
00093     if ( mRequest.filterType() == QgsFeatureRequest::FilterRect )
00094     {
00095       if ( fetchNextChangedGeomFeature( f ) )
00096         return true;
00097 
00098       // no more changed geometries
00099     }
00100 
00101     if ( fetchNextAddedFeature( f ) )
00102       return true;
00103 
00104     // no more added features
00105   }
00106 
00107   while ( mProviderIterator.nextFeature( f ) )
00108   {
00109     if ( mFetchConsidered.contains( f.id() ) )
00110       continue;
00111 
00112     // TODO[MD]: just one resize of attributes
00113     f.setFields( &L->mUpdatedFields );
00114 
00115     // update attributes
00116     if ( editBuffer )
00117       editBuffer->updateChangedAttributes( f );
00118 
00119     if ( !mFetchJoinInfo.isEmpty() )
00120       addJoinedAttributes( f );
00121 
00122     // update geometry
00123     if ( editBuffer && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
00124       editBuffer->updateFeatureGeometry( f );
00125 
00126     return true;
00127   }
00128 
00129   close();
00130   return false;
00131 }
00132 
00133 
00134 
00135 bool QgsVectorLayerFeatureIterator::rewind()
00136 {
00137   if ( mClosed )
00138     return false;
00139 
00140   if ( mRequest.filterType() == QgsFeatureRequest::FilterFid )
00141   {
00142     mFetchedFid = false;
00143   }
00144   else
00145   {
00146     mProviderIterator.rewind();
00147     rewindEditBuffer();
00148   }
00149 
00150   return true;
00151 }
00152 
00153 bool QgsVectorLayerFeatureIterator::close()
00154 {
00155   if ( mClosed )
00156     return false;
00157 
00158   mProviderIterator.close();
00159 
00160   mClosed = true;
00161   return true;
00162 }
00163 
00164 
00165 
00166 
00167 bool QgsVectorLayerFeatureIterator::fetchNextAddedFeature( QgsFeature& f )
00168 {
00169   QgsVectorLayerEditBuffer* editBuffer = L->editBuffer();
00170 
00171   for ( ; mFetchAddedFeaturesIt != editBuffer->mAddedFeatures.end(); mFetchAddedFeaturesIt++ )
00172   {
00173     QgsFeatureId fid = mFetchAddedFeaturesIt->id();
00174 
00175     if ( mFetchConsidered.contains( fid ) )
00176       // must have changed geometry outside rectangle
00177       continue;
00178 
00179     if ( mRequest.filterType() == QgsFeatureRequest::FilterRect &&
00180          mFetchAddedFeaturesIt->geometry() &&
00181          !mFetchAddedFeaturesIt->geometry()->intersects( mRequest.filterRect() ) )
00182       // skip added features not in rectangle
00183       continue;
00184 
00185     useAddedFeature( *mFetchAddedFeaturesIt, f );
00186 
00187     mFetchAddedFeaturesIt++;
00188     return true;
00189   }
00190 
00191   return false; // no more added features
00192 }
00193 
00194 
00195 void QgsVectorLayerFeatureIterator::useAddedFeature( const QgsFeature& src, QgsFeature& f )
00196 {
00197   f.setFeatureId( src.id() );
00198   f.setValid( true );
00199   f.setFields( &L->mUpdatedFields );
00200 
00201   if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
00202     f.setGeometry( *src.geometry() );
00203 
00204   // TODO[MD]: if subset set just some attributes
00205 
00206   f.setAttributes( src.attributes() );
00207 
00208   if ( !mFetchJoinInfo.isEmpty() )
00209     addJoinedAttributes( f );
00210 }
00211 
00212 
00213 
00214 bool QgsVectorLayerFeatureIterator::fetchNextChangedGeomFeature( QgsFeature& f )
00215 {
00216   QgsVectorLayerEditBuffer* editBuffer = L->editBuffer();
00217 
00218   // check if changed geometries are in rectangle
00219   for ( ; mFetchChangedGeomIt != editBuffer->mChangedGeometries.end(); mFetchChangedGeomIt++ )
00220   {
00221     QgsFeatureId fid = mFetchChangedGeomIt.key();
00222 
00223     if ( mFetchConsidered.contains( fid ) )
00224       // skip deleted features
00225       continue;
00226 
00227     mFetchConsidered << fid;
00228 
00229     if ( !mFetchChangedGeomIt->intersects( mRequest.filterRect() ) )
00230       // skip changed geometries not in rectangle and don't check again
00231       continue;
00232 
00233     useChangedAttributeFeature( fid, *mFetchChangedGeomIt, f );
00234 
00235     // return complete feature
00236     mFetchChangedGeomIt++;
00237     return true;
00238   }
00239 
00240   return false; // no more changed geometries
00241 }
00242 
00243 
00244 void QgsVectorLayerFeatureIterator::useChangedAttributeFeature( QgsFeatureId fid, const QgsGeometry& geom, QgsFeature& f )
00245 {
00246   f.setFeatureId( fid );
00247   f.setValid( true );
00248   f.setFields( &L->mUpdatedFields );
00249 
00250   if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
00251     f.setGeometry( geom );
00252 
00253   bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
00254   if ( !subsetAttrs || ( subsetAttrs && mRequest.subsetOfAttributes().count() > 0 ) )
00255   {
00256     // retrieve attributes from provider
00257     QgsFeature tmp;
00258     //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
00259     QgsFeatureRequest request;
00260     request.setFilterFid( fid ).setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( mProviderRequest.subsetOfAttributes() );
00261     QgsFeatureIterator fi = L->dataProvider()->getFeatures( request );
00262     if ( fi.nextFeature( tmp ) )
00263     {
00264       if ( L->editBuffer() )
00265         L->editBuffer()->updateChangedAttributes( tmp );
00266       f.setAttributes( tmp.attributes() );
00267     }
00268   }
00269 
00270   if ( !mFetchJoinInfo.isEmpty() )
00271     addJoinedAttributes( f );
00272 }
00273 
00274 
00275 
00276 void QgsVectorLayerFeatureIterator::rewindEditBuffer()
00277 {
00278   QgsVectorLayerEditBuffer* editBuffer = L->editBuffer();
00279 
00280   mFetchConsidered = editBuffer ? editBuffer->mDeletedFeatureIds : QSet<QgsFeatureId>();
00281 
00282   if ( editBuffer )
00283   {
00284     mFetchAddedFeaturesIt = editBuffer->mAddedFeatures.begin();
00285     mFetchChangedGeomIt = editBuffer->mChangedGeometries.begin();
00286   }
00287 }
00288 
00289 
00290 
00291 void QgsVectorLayerFeatureIterator::prepareJoins()
00292 {
00293   QgsAttributeList fetchAttributes = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) ? mRequest.subsetOfAttributes() : L->pendingAllAttributesList();
00294   QgsAttributeList sourceJoinFields; // attributes that also need to be fetched from this layer in order to have joins working
00295 
00296   mFetchJoinInfo.clear();
00297 
00298   QgsVectorLayerJoinBuffer* joinBuffer = L->mJoinBuffer;
00299   const QgsFields& fields = L->pendingFields();
00300 
00301   for ( QgsAttributeList::const_iterator attIt = fetchAttributes.constBegin(); attIt != fetchAttributes.constEnd(); ++attIt )
00302   {
00303     if ( fields.fieldOrigin( *attIt ) != QgsFields::OriginJoin )
00304       continue;
00305 
00306     int sourceLayerIndex;
00307     const QgsVectorJoinInfo* joinInfo = joinBuffer->joinForFieldIndex( *attIt, fields, sourceLayerIndex );
00308     Q_ASSERT( joinInfo );
00309 
00310     QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo->joinLayerId ) );
00311     Q_ASSERT( joinLayer );
00312 
00313     if ( !mFetchJoinInfo.contains( joinLayer ) )
00314     {
00315       FetchJoinInfo info;
00316       info.joinInfo = joinInfo;
00317       info.joinLayer = joinLayer;
00318 
00319       if ( joinInfo->targetFieldName.isEmpty() )
00320         info.targetField = joinInfo->targetFieldIndex;    //for compatibility with 1.x
00321       else
00322         info.targetField = fields.indexFromName( joinInfo->targetFieldName );
00323 
00324       if ( joinInfo->joinFieldName.isEmpty() )
00325         info.joinField = joinInfo->joinFieldIndex;      //for compatibility with 1.x
00326       else
00327         info.joinField = joinLayer->pendingFields().indexFromName( joinInfo->joinFieldName );
00328 
00329       info.indexOffset = *attIt - sourceLayerIndex;
00330       if ( info.joinField < sourceLayerIndex )
00331         info.indexOffset++;
00332 
00333       // for joined fields, we always need to request the targetField from the provider too
00334       if ( !fetchAttributes.contains( info.targetField ) )
00335         sourceJoinFields << info.targetField;
00336 
00337       mFetchJoinInfo.insert( joinLayer, info );
00338     }
00339 
00340     // store field source index - we'll need it when fetching from provider
00341     mFetchJoinInfo[ joinLayer ].attributes.push_back( sourceLayerIndex );
00342   }
00343 
00344   // add sourceJoinFields if we're using a subset
00345   if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
00346     mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() + sourceJoinFields );
00347 }
00348 
00349 
00350 void QgsVectorLayerFeatureIterator::addJoinedAttributes( QgsFeature &f )
00351 {
00352   // make sure we have space for newly added attributes
00353   f.attributes().resize( L->pendingFields().count() );  // f.attributes().count() + mJoinedAttributesCount );
00354 
00355   QMap<QgsVectorLayer*, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
00356   for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
00357   {
00358     const FetchJoinInfo& info = joinIt.value();
00359     Q_ASSERT( joinIt.key() );
00360 
00361     QVariant targetFieldValue = f.attribute( info.targetField );
00362     if ( !targetFieldValue.isValid() )
00363       continue;
00364 
00365     const QHash< QString, QgsAttributes>& memoryCache = info.joinInfo->cachedAttributes;
00366     if ( memoryCache.isEmpty() )
00367       info.addJoinedAttributesDirect( f, targetFieldValue );
00368     else
00369       info.addJoinedAttributesCached( f, targetFieldValue );
00370   }
00371 }
00372 
00373 
00374 
00375 void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesCached( QgsFeature& f, const QVariant& joinValue ) const
00376 {
00377   const QHash<QString, QgsAttributes>& memoryCache = joinInfo->cachedAttributes;
00378   QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
00379   if ( it == memoryCache.end() )
00380     return; // joined value not found -> leaving the attributes empty (null)
00381 
00382   int index = indexOffset;
00383 
00384   const QgsAttributes& featureAttributes = it.value();
00385   for ( int i = 0; i < featureAttributes.count(); ++i )
00386   {
00387     // skip the join field to avoid double field names (fields often have the same name)
00388     if ( i == joinField )
00389       continue;
00390 
00391     f.setAttribute( index++, featureAttributes[i] );
00392   }
00393 }
00394 
00395 
00396 
00397 void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( QgsFeature& f, const QVariant& joinValue ) const
00398 {
00399   // no memory cache, query the joined values by setting substring
00400   QString subsetString = joinLayer->dataProvider()->subsetString(); // provider might already have a subset string
00401   QString bkSubsetString = subsetString;
00402   if ( !subsetString.isEmpty() )
00403   {
00404     subsetString.append( " AND " );
00405   }
00406 
00407   QString joinFieldName;
00408   if ( joinInfo->joinFieldName.isEmpty() && joinInfo->joinFieldIndex >= 0 && joinInfo->joinFieldIndex < joinLayer->pendingFields().count() )
00409     joinFieldName = joinLayer->pendingFields().field( joinInfo->joinFieldIndex ).name();   // for compatibility with 1.x
00410   else
00411     joinFieldName = joinInfo->joinFieldName;
00412 
00413   subsetString.append( "\"" + joinFieldName + "\"" + " = " + "\"" + joinValue.toString() + "\"" );
00414   joinLayer->dataProvider()->setSubsetString( subsetString, false );
00415 
00416   // select (no geometry)
00417   QgsFeatureRequest request;
00418   request.setFlags( QgsFeatureRequest::NoGeometry );
00419   request.setSubsetOfAttributes( attributes );
00420   QgsFeatureIterator fi = joinLayer->getFeatures( request );
00421 
00422   // get first feature
00423   QgsFeature fet;
00424   if ( fi.nextFeature( fet ) )
00425   {
00426     int index = indexOffset;
00427     const QgsAttributes& attr = fet.attributes();
00428     for ( int i = 0; i < attr.count(); ++i )
00429     {
00430       if ( i == joinField )
00431         continue;
00432 
00433       f.setAttribute( index++, attr[i] );
00434     }
00435   }
00436   else
00437   {
00438     // no suitable join feature found, keeping empty (null) attributes
00439   }
00440 
00441   joinLayer->dataProvider()->setSubsetString( bkSubsetString, false );
00442 }
00443 
00444 
00445 
00446 
00447 bool QgsVectorLayerFeatureIterator::nextFeatureFid( QgsFeature& f )
00448 {
00449   QgsVectorLayerEditBuffer* editBuffer = L->editBuffer();
00450   QgsFeatureId featureId = mRequest.filterFid();
00451 
00452   if ( editBuffer )
00453   {
00454     // deleted already?
00455     if ( editBuffer->mDeletedFeatureIds.contains( featureId ) )
00456       return false;
00457 
00458     // has changed geometry?
00459     if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && editBuffer->mChangedGeometries.contains( featureId ) )
00460     {
00461       useChangedAttributeFeature( featureId, editBuffer->mChangedGeometries[featureId], f );
00462       return true;
00463     }
00464 
00465     // added features
00466     for ( QgsFeatureMap::iterator iter = editBuffer->mAddedFeatures.begin(); iter != editBuffer->mAddedFeatures.end(); ++iter )
00467     {
00468       if ( iter->id() == featureId )
00469       {
00470         useAddedFeature( *iter, f );
00471         return true;
00472       }
00473     }
00474   }
00475 
00476   // regular features
00477   QgsFeatureIterator fi = L->dataProvider()->getFeatures( mProviderRequest );
00478   if ( fi.nextFeature( f ) )
00479   {
00480     if ( editBuffer )
00481       editBuffer->updateChangedAttributes( f );
00482 
00483     if ( !mFetchJoinInfo.isEmpty() )
00484       addJoinedAttributes( f );
00485 
00486     return true;
00487   }
00488 
00489   return false;
00490 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines