|
QGIS API Documentation
master-59fd5e0
|
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 }