QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsvectorlayerfeatureiterator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerfeatureiterator.cpp
3  ---------------------
4  begin : Dezember 2012
5  copyright : (C) 2012 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
16 
18 #include "qgsgeometrysimplifier.h"
19 #include "qgsmaplayerregistry.h"
20 #include "qgssimplifymethod.h"
21 #include "qgsvectordataprovider.h"
23 #include "qgsvectorlayer.h"
25 
27 {
29  mFields = layer->pendingFields();
30  mJoinBuffer = layer->mJoinBuffer->clone();
31  mExpressionFieldBuffer = new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer );
32 
33  mCanBeSimplified = layer->hasGeometryType() && layer->geometryType() != QGis::Point;
34 
35  mHasEditBuffer = layer->editBuffer();
36  if ( mHasEditBuffer )
37  {
38 #if 0
39  // TODO[MD]: after merge
40  if ( request.filterType() == QgsFeatureRequest::FilterFid )
41  {
42 
43  // only copy relevant parts
44  if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
45  mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
46 
47  if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
48  mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
49 
50  if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
51  mDeletedFeatureIds.insert( request.filterFid() );
52 
53  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
54  mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
55 
56  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
57  mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
58  }
59  else
60  {
61 #endif
66  mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
68 #if 0
69  }
70 #endif
71  }
72 }
73 
75 {
76  delete mJoinBuffer;
79 }
80 
82 {
83  // return feature iterator that does not own this source
84  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
85 }
86 
87 
90  , mFetchedFid( false )
91  , mEditGeometrySimplifier( 0 )
92 {
93 
94  // prepare joins: may add more attributes to fetch (in order to allow join)
96  prepareJoins();
97 
99 
100  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
101 
102  // by default provider's request is the same
104 
106  {
107  // prepare list of attributes to match provider fields
108  QgsAttributeList providerSubset;
110  int nPendingFields = mSource->mFields.count();
111  for ( int i = 0; i < subset.count(); ++i )
112  {
113  int attrIndex = subset[i];
114  if ( attrIndex < 0 || attrIndex >= nPendingFields ) continue;
115  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
116  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
117  }
118  mProviderRequest.setSubsetOfAttributes( providerSubset );
119  }
120 
121  if ( mSource->mHasEditBuffer )
122  {
125  }
126 
127  if ( request.filterType() == QgsFeatureRequest::FilterFid )
128  {
129  mFetchedFid = false;
130  }
131  else // no filter or filter by rect
132  {
133  if ( mSource->mHasEditBuffer )
134  {
136  }
137  else
138  {
140  }
141 
143  }
144 
146  {
148  }
149 }
150 
151 
153 {
154  delete mEditGeometrySimplifier;
155  mEditGeometrySimplifier = NULL;
156 
157  qDeleteAll( mExpressionFieldInfo.values() );
158 
159  close();
160 }
161 
162 
163 
165 {
166  f.setValid( false );
167 
168  if ( mClosed )
169  return false;
170 
172  {
173  if ( mFetchedFid )
174  return false;
175  bool res = nextFeatureFid( f );
176  mFetchedFid = true;
177  return res;
178  }
179 
181  {
182  if ( fetchNextChangedGeomFeature( f ) )
183  return true;
184 
185  // no more changed geometries
186  }
187 
189  {
191  return true;
192 
193  // no more changed features
194  }
195 
196  while ( fetchNextAddedFeature( f ) )
197  {
198  return true;
199  }
200  // no more added features
201 
202  if ( mProviderIterator.isClosed() )
203  {
206  }
207 
208  while ( mProviderIterator.nextFeature( f ) )
209  {
210  if ( mFetchConsidered.contains( f.id() ) )
211  continue;
212 
213  // TODO[MD]: just one resize of attributes
214  f.setFields( &mSource->mFields );
215 
216  // update attributes
217  if ( mSource->mHasEditBuffer )
219 
220  if ( mHasVirtualAttributes )
222 
223  // update geometry
224  // TODO[MK]: FilterRect check after updating the geometry
227 
228  return true;
229  }
230  // no more provider features
231 
232  close();
233  return false;
234 }
235 
236 
237 
239 {
240  if ( mClosed )
241  return false;
242 
244  {
245  mFetchedFid = false;
246  }
247  else
248  {
251  }
252 
253  return true;
254 }
255 
257 {
258  if ( mClosed )
259  return false;
260 
262 
263  iteratorClosed();
264 
265  mClosed = true;
266  return true;
267 }
268 
269 
270 
271 
273 {
274  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
275  {
277 
278  if ( mFetchConsidered.contains( fid ) )
279  // must have changed geometry outside rectangle
280  continue;
281 
283  // skip features which are not accepted by the filter
284  continue;
285 
287 
288  return true;
289  }
290 
292  return false; // no more added features
293 }
294 
295 
297 {
298  f.setFeatureId( src.id() );
299  f.setValid( true );
300  f.setFields( &mSource->mFields );
301 
302  if ( src.geometry() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
303  {
304  f.setGeometry( *src.geometry() );
305 
306  // simplify the edited geometry using its simplifier configured
307  if ( mEditGeometrySimplifier )
308  {
309  QgsGeometry* geometry = f.geometry();
310  QGis::GeometryType geometryType = geometry->type();
311  if ( geometryType == QGis::Line || geometryType == QGis::Polygon ) mEditGeometrySimplifier->simplifyGeometry( geometry );
312  }
313  }
314 
315  // TODO[MD]: if subset set just some attributes
316 
317  f.setAttributes( src.attributes() );
318 
319  if ( mHasVirtualAttributes )
321 }
322 
323 
324 
326 {
327  // check if changed geometries are in rectangle
329  {
330  QgsFeatureId fid = mFetchChangedGeomIt.key();
331 
332  if ( mFetchConsidered.contains( fid ) )
333  // skip deleted features
334  continue;
335 
336  mFetchConsidered << fid;
337 
338  if ( !mFetchChangedGeomIt->intersects( mRequest.filterRect() ) )
339  // skip changed geometries not in rectangle and don't check again
340  continue;
341 
343 
344  // return complete feature
346  return true;
347  }
348 
349  return false; // no more changed geometries
350 }
351 
353 {
355  {
356  mFetchConsidered << f.id();
357 
359 
360  if ( mHasVirtualAttributes )
362 
364  {
365  if ( mRequest.filterExpression()->evaluate( &f ).toBool() )
366  {
367  return true;
368  }
369  }
370  else
371  {
372  return true;
373  }
374  }
375 
376  return false;
377 }
378 
379 
381 {
382  f.setFeatureId( fid );
383  f.setValid( true );
384  f.setFields( &mSource->mFields );
385 
387  {
388  f.setGeometry( geom );
389 
390  // simplify the edited geometry using its simplifier configured
391  if ( mEditGeometrySimplifier )
392  {
393  QgsGeometry* geometry = f.geometry();
394  QGis::GeometryType geometryType = geometry->type();
395  if ( geometryType == QGis::Line || geometryType == QGis::Polygon ) mEditGeometrySimplifier->simplifyGeometry( geometry );
396  }
397  }
398 
399  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
400  if ( !subsetAttrs || ( subsetAttrs && mRequest.subsetOfAttributes().count() > 0 ) )
401  {
402  // retrieve attributes from provider
403  QgsFeature tmp;
404  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
405  QgsFeatureRequest request;
407  if ( subsetAttrs )
408  {
410  }
412  if ( fi.nextFeature( tmp ) )
413  {
416  f.setAttributes( tmp.attributes() );
417  }
418  }
419 
421 }
422 
423 
424 
426 {
428 
431 }
432 
433 
434 
436 {
438  QgsAttributeList sourceJoinFields; // attributes that also need to be fetched from this layer in order to have joins working
439 
440  mFetchJoinInfo.clear();
441 
442  for ( QgsAttributeList::const_iterator attIt = fetchAttributes.constBegin(); attIt != fetchAttributes.constEnd(); ++attIt )
443  {
444  if ( !mSource->mFields.exists( *attIt ) )
445  continue;
446 
447  if ( mSource->mFields.fieldOrigin( *attIt ) != QgsFields::OriginJoin )
448  continue;
449 
450  int sourceLayerIndex;
451  const QgsVectorJoinInfo* joinInfo = mSource->mJoinBuffer->joinForFieldIndex( *attIt, mSource->mFields, sourceLayerIndex );
452  Q_ASSERT( joinInfo );
453 
454  QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo->joinLayerId ) );
455  Q_ASSERT( joinLayer );
456 
457  if ( !mFetchJoinInfo.contains( joinInfo ) )
458  {
459  FetchJoinInfo info;
460  info.joinInfo = joinInfo;
461  info.joinLayer = joinLayer;
463 
464  if ( joinInfo->targetFieldName.isEmpty() )
465  info.targetField = joinInfo->targetFieldIndex; //for compatibility with 1.x
466  else
468 
469  if ( joinInfo->joinFieldName.isEmpty() )
470  info.joinField = joinInfo->joinFieldIndex; //for compatibility with 1.x
471  else
472  info.joinField = joinLayer->pendingFields().indexFromName( joinInfo->joinFieldName );
473 
474  // for joined fields, we always need to request the targetField from the provider too
475  if ( !fetchAttributes.contains( info.targetField ) )
476  sourceJoinFields << info.targetField;
477 
478  mFetchJoinInfo.insert( joinInfo, info );
479  }
480 
481  // store field source index - we'll need it when fetching from provider
482  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
483  }
484 
485  // add sourceJoinFields if we're using a subset
488 }
489 
491 {
492  const QList<QgsExpressionFieldBuffer::ExpressionField> exps = mSource->mExpressionFieldBuffer->expressions();
493 
494  for ( int i = 0; i < mSource->mFields.count(); i++ )
495  {
497  {
498  // Only prepare if there is no subset defined or the subset contains this field
500  || mRequest.subsetOfAttributes().contains( i ) )
501  {
502  int oi = mSource->mFields.fieldOriginIndex( i );
503  QgsExpression* exp = new QgsExpression( exps[oi].expression );
504  exp->prepare( mSource->mFields );
505  mExpressionFieldInfo.insert( i, exp );
506 
508  {
509  QgsAttributeList attrs;
510  Q_FOREACH ( const QString& col, exp->referencedColumns() )
511  {
512  attrs.append( mSource->mFields.fieldNameIndex( col ) );
513  }
514 
516  }
517 
518  if ( exp->needsGeometry() )
519  {
520  mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
521  }
522  }
523  }
524  }
525 }
526 
528 {
529  QMap<const QgsVectorJoinInfo*, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
530  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
531  {
532  const FetchJoinInfo& info = joinIt.value();
533  Q_ASSERT( joinIt.key() );
534 
535  QVariant targetFieldValue = f.attribute( info.targetField );
536  if ( !targetFieldValue.isValid() )
537  continue;
538 
539  const QHash< QString, QgsAttributes>& memoryCache = info.joinInfo->cachedAttributes;
540  if ( memoryCache.isEmpty() )
541  info.addJoinedAttributesDirect( f, targetFieldValue );
542  else
543  info.addJoinedAttributesCached( f, targetFieldValue );
544  }
545 }
546 
548 {
549  // make sure we have space for newly added attributes
550  f.attributes().resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
551 
552  if ( !mFetchJoinInfo.isEmpty() )
553  addJoinedAttributes( f );
554 
555  if ( !mExpressionFieldInfo.isEmpty() )
556  {
557  QMap<int, QgsExpression*>::ConstIterator it = mExpressionFieldInfo.constBegin();
558 
559  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
560  {
561  QgsExpression* exp = it.value();
562  QVariant val = exp->evaluate( f );
563  mSource->mFields.at( it.key() ).convertCompatible( val );;
564  f.setAttribute( it.key(), val );
565  }
566  }
567 }
568 
570 {
571  delete mEditGeometrySimplifier;
572  mEditGeometrySimplifier = NULL;
573 
574  // setup simplification for edited geometries to fetch
576  {
577  mEditGeometrySimplifier = QgsSimplifyMethod::createGeometrySimplifier( simplifyMethod );
578  return mEditGeometrySimplifier != NULL;
579  }
580  return false;
581 }
582 
583 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
584 {
585  Q_UNUSED( methodType );
586 #if 0
587  // TODO[MD]: after merge
588  QgsVectorDataProvider* provider = L->dataProvider();
589 
590  if ( provider && methodType != QgsSimplifyMethod::NoSimplification )
591  {
592  int capabilities = provider->capabilities();
593 
594  if ( methodType == QgsSimplifyMethod::OptimizeForRendering )
595  {
596  return ( capabilities & QgsVectorDataProvider::SimplifyGeometries );
597  }
598  else if ( methodType == QgsSimplifyMethod::PreserveTopology )
599  {
601  }
602  }
603 #endif
604  return false;
605 }
606 
607 
609 {
610  const QHash<QString, QgsAttributes>& memoryCache = joinInfo->cachedAttributes;
611  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
612  if ( it == memoryCache.constEnd() )
613  return; // joined value not found -> leaving the attributes empty (null)
614 
615  int index = indexOffset;
616 
617  const QgsAttributes& featureAttributes = it.value();
618  for ( int i = 0; i < featureAttributes.count(); ++i )
619  {
620  f.setAttribute( index++, featureAttributes[i] );
621  }
622 }
623 
624 
625 
627 {
628  // no memory cache, query the joined values by setting substring
629  QString subsetString = joinLayer->dataProvider()->subsetString(); // provider might already have a subset string
630  QString bkSubsetString = subsetString;
631  if ( !subsetString.isEmpty() )
632  {
633  subsetString.prepend( "(" ).append( ") AND " );
634  }
635 
636  QString joinFieldName;
637  if ( joinInfo->joinFieldName.isEmpty() && joinInfo->joinFieldIndex >= 0 && joinInfo->joinFieldIndex < joinLayer->pendingFields().count() )
638  joinFieldName = joinLayer->pendingFields().field( joinInfo->joinFieldIndex ).name(); // for compatibility with 1.x
639  else
640  joinFieldName = joinInfo->joinFieldName;
641 
642  subsetString.append( QString( "\"%1\"" ).arg( joinFieldName ) );
643 
644  if ( joinValue.isNull() )
645  {
646  subsetString += " IS NULL";
647  }
648  else
649  {
650  QString v = joinValue.toString();
651  switch ( joinValue.type() )
652  {
653  case QVariant::Int:
654  case QVariant::LongLong:
655  case QVariant::Double:
656  break;
657 
658  default:
659  case QVariant::String:
660  v.replace( "'", "''" );
661  v.prepend( "'" ).append( "'" );
662  break;
663  }
664  subsetString += "=" + v;
665  }
666 
667  joinLayer->dataProvider()->setSubsetString( subsetString, false );
668 
669  // maybe user requested just a subset of layer's attributes
670  // so we do not have to cache everything
671  bool hasSubset = joinInfo->joinFieldNamesSubset();
672  QVector<int> subsetIndices;
673  if ( hasSubset )
674  subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, *joinInfo->joinFieldNamesSubset() );
675 
676  // select (no geometry)
677  QgsFeatureRequest request;
679  request.setSubsetOfAttributes( attributes );
680  QgsFeatureIterator fi = joinLayer->getFeatures( request );
681 
682  // get first feature
683  QgsFeature fet;
684  if ( fi.nextFeature( fet ) )
685  {
686  int index = indexOffset;
687  const QgsAttributes& attr = fet.attributes();
688  if ( hasSubset )
689  {
690  for ( int i = 0; i < subsetIndices.count(); ++i )
691  f.setAttribute( index++, attr[ subsetIndices[i] ] );
692  }
693  else
694  {
695  // use all fields except for the one used for join (has same value as exiting field in target layer)
696  for ( int i = 0; i < attr.count(); ++i )
697  {
698  if ( i == joinField )
699  continue;
700 
701  f.setAttribute( index++, attr[i] );
702  }
703  }
704  }
705  else
706  {
707  // no suitable join feature found, keeping empty (null) attributes
708  }
709 
710  joinLayer->dataProvider()->setSubsetString( bkSubsetString, false );
711 }
712 
713 
714 
715 
717 {
718  QgsFeatureId featureId = mRequest.filterFid();
719 
720  // deleted already?
721  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
722  return false;
723 
724  // has changed geometry?
725  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
726  {
727  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
728  return true;
729  }
730 
731  // added features
732  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
733  {
734  if ( iter->id() == featureId )
735  {
736  useAddedFeature( *iter, f );
737  return true;
738  }
739  }
740 
741  // regular features
743  if ( fi.nextFeature( f ) )
744  {
745  if ( mSource->mHasEditBuffer )
747 
748  if ( mHasVirtualAttributes )
750 
751  return true;
752  }
753 
754  return false;
755 }
756 
758 {
759  QgsAttributes& attrs = f.attributes();
760 
761  // remove all attributes that will disappear - from higher indices to lower
762  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
763  {
764  attrs.remove( mSource->mDeletedAttributeIds[idx] );
765  }
766 
767  // adjust size to accommodate added attributes
768  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
769 
770  // update changed attributes
771  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
772  {
774  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
775  attrs[it.key()] = it.value();
776  }
777 }
778 
780 {
781  if ( mSource->mChangedGeometries.contains( f.id() ) )
783 }
784