[QGIS Commit] r13881 - in branches/threading-branch: python/core src/analysis/interpolation src/core src/gui src/providers/ogr src/providers/osm src/providers/postgres

svn_qgis at osgeo.org svn_qgis at osgeo.org
Sat Jul 3 12:50:45 EDT 2010


Author: wonder
Date: 2010-07-03 16:50:45 +0000 (Sat, 03 Jul 2010)
New Revision: 13881

Added:
   branches/threading-branch/src/core/qgsvectorlayeriterator.cpp
   branches/threading-branch/src/core/qgsvectorlayeriterator.h
   branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.cpp
   branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.h
   branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.cpp
   branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.h
Modified:
   branches/threading-branch/python/core/qgsvectordataprovider.sip
   branches/threading-branch/python/core/qgsvectorlayer.sip
   branches/threading-branch/src/analysis/interpolation/qgsinterpolator.cpp
   branches/threading-branch/src/core/CMakeLists.txt
   branches/threading-branch/src/core/qgsvectordataprovider.cpp
   branches/threading-branch/src/core/qgsvectordataprovider.h
   branches/threading-branch/src/core/qgsvectorlayer.cpp
   branches/threading-branch/src/core/qgsvectorlayer.h
   branches/threading-branch/src/gui/qgsmaptip.cpp
   branches/threading-branch/src/providers/ogr/CMakeLists.txt
   branches/threading-branch/src/providers/ogr/qgsogrprovider.cpp
   branches/threading-branch/src/providers/ogr/qgsogrprovider.h
   branches/threading-branch/src/providers/osm/osmprovider.cpp
   branches/threading-branch/src/providers/postgres/CMakeLists.txt
   branches/threading-branch/src/providers/postgres/qgspostgresprovider.cpp
   branches/threading-branch/src/providers/postgres/qgspostgresprovider.h
Log:
Introduced new API for access to vector layers and vector data providers.
New API implemented so far only for OGR and PostGIS providers - both using locking to control read access to data from multiple threads.


Modified: branches/threading-branch/python/core/qgsvectordataprovider.sip
===================================================================
--- branches/threading-branch/python/core/qgsvectordataprovider.sip	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/python/core/qgsvectordataprovider.sip	2010-07-03 16:50:45 UTC (rev 13881)
@@ -1,4 +1,39 @@
 
+typedef QList<int> QgsAttributeList;
+
+class QgsFeatureIterator
+{
+%TypeHeaderCode
+#include <qgsvectordataprovider.h>
+%End
+
+public:
+  //! construct invalid iterator
+  QgsFeatureIterator();
+  //! construct an iterator for iterating an instance of vector data provider
+  //QgsFeatureIterator(QgsVectorDataProviderIterator* iter);
+  //! construct an iterator for iterating an instance of vector layer (data provider + uncommitted data)
+  //QgsFeatureIterator(VectorLayerIterator* layerIter);
+  //! copy constructor copies the provider iterator, increases ref.count
+  QgsFeatureIterator(const QgsFeatureIterator& fi);
+  //! destructor deletes the provider iterator if it has no more references
+  ~QgsFeatureIterator();
+
+  // TODO? QgsFeatureIterator& operator=(const QgsFeatureIterator& other);
+
+  bool nextFeature(QgsFeature& f);
+  bool rewind();
+  bool close();
+
+  //! find out whether the iterator is still valid or closed already
+  bool isClosed();
+
+};
+
+bool operator== (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2);
+bool operator!= (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2);
+
+
 class QgsVectorDataProvider : QgsDataProvider
 {
 %TypeHeaderCode
@@ -82,7 +117,17 @@
        */
       virtual long updateFeatureCount();
 
-      /** 
+      /**
+       * Start iterating over features of the vector data provider.
+       * For new code, consider using this method instead of select/nextFeature combo.
+       * @note Added in v1.6
+       */
+      virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                              QgsRectangle rect = QgsRectangle(),
+                                              bool fetchGeometry = true,
+                                              bool useIntersect = false );
+
+      /**
        * Gets the feature at the given feature ID.
        * @param featureId id of the feature
        * @param feature feature which will receive the data

Modified: branches/threading-branch/python/core/qgsvectorlayer.sip
===================================================================
--- branches/threading-branch/python/core/qgsvectorlayer.sip	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/python/core/qgsvectorlayer.sip	2010-07-03 16:50:45 UTC (rev 13881)
@@ -132,9 +132,9 @@
   void setUsingRendererV2(bool usingRendererV2);
     
   /** Draw layer with renderer V2. Added in QGIS 1.4 */
-  void drawRendererV2( QgsRenderContext& rendererContext, bool labeling );
+  void drawRendererV2( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi );
   /** Draw layer with renderer V2 using symbol levels. Added in QGIS 1.4 */
-  void drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling );
+  void drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi );
 
   /** Returns point, line or polygon */
   QGis::GeometryType geometryType() const;
@@ -207,6 +207,15 @@
 
   bool nextFeature(QgsFeature& feature);
 
+  /**
+   * Start iterating over features of the layer.
+   * For new code, consider using this method instead of select/nextFeature combo.
+   * @note Added in v1.6
+   */
+  QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                  QgsRectangle rect = QgsRectangle(),
+                                  bool fetchGeometry = true,
+                                  bool useIntersect = false );
 
   /**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
    @return true in case of success*/

Modified: branches/threading-branch/src/analysis/interpolation/qgsinterpolator.cpp
===================================================================
--- branches/threading-branch/src/analysis/interpolation/qgsinterpolator.cpp	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/analysis/interpolation/qgsinterpolator.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -16,7 +16,7 @@
  ***************************************************************************/
 
 #include "qgsinterpolator.h"
-#include "qgsvectordataprovider.h"
+#include "qgsvectorlayer.h"
 #include "qgsgeometry.h"
 #ifndef Q_OS_MACX
 #include <cmath>

Modified: branches/threading-branch/src/core/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/core/CMakeLists.txt	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/CMakeLists.txt	2010-07-03 16:50:45 UTC (rev 13881)
@@ -87,6 +87,7 @@
   qgsvectordataprovider.cpp
   qgsvectorfilewriter.cpp
   qgsvectorlayer.cpp
+  qgsvectorlayeriterator.cpp
   qgsvectorlayerundocommand.cpp
   qgsvectoroverlay.cpp
 

Modified: branches/threading-branch/src/core/qgsvectordataprovider.cpp
===================================================================
--- branches/threading-branch/src/core/qgsvectordataprovider.cpp	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/qgsvectordataprovider.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -25,6 +25,114 @@
 #include "qgsfield.h"
 #include "qgslogger.h"
 
+
+
+QgsVectorDataProviderIterator::QgsVectorDataProviderIterator(QgsAttributeList fetchAttributes,
+                                                             QgsRectangle rect,
+                                                             bool fetchGeometry,
+                                                             bool useIntersect )
+ : mFetchAttributes(fetchAttributes),
+   mFetchGeometry(fetchGeometry),
+   mRect(rect),
+   mUseIntersect(useIntersect),
+   refs(0),
+   mClosed(false)
+{
+}
+
+QgsVectorDataProviderIterator::~QgsVectorDataProviderIterator()
+{
+}
+
+void QgsVectorDataProviderIterator::ref()
+{
+  refs++;
+  QgsDebugMsg("ADDED REF: "+QString::number(refs));
+}
+void QgsVectorDataProviderIterator::deref()
+{
+  refs--;
+  QgsDebugMsg("REMOVED REF: "+QString::number(refs));
+  if (!refs)
+    delete this;
+}
+
+////////
+
+QgsFeatureIterator::QgsFeatureIterator()
+  : provIter(NULL)
+{
+  QgsDebugMsg("CREATED INVALID ITER");
+}
+
+QgsFeatureIterator::QgsFeatureIterator(QgsVectorDataProviderIterator* iter)
+  : provIter(iter)
+{
+  QgsDebugMsg("CREATED GOOD ITER");
+  if (iter)
+    iter->ref();
+}
+
+QgsFeatureIterator::QgsFeatureIterator(const QgsFeatureIterator& fi)
+  : provIter(fi.provIter)
+{
+  QgsDebugMsg("CREATED COPIED ITER");
+  if (provIter)
+    provIter->ref();
+}
+
+QgsFeatureIterator::~QgsFeatureIterator()
+{
+  QgsDebugMsg("DELETING ITER");
+  if (provIter)
+    provIter->deref();
+}
+
+QgsFeatureIterator& QgsFeatureIterator::operator=(const QgsFeatureIterator& other)
+{
+  if (this != &other)
+  {
+    if (provIter)
+      provIter->deref();
+    provIter = other.provIter;
+    if (provIter)
+      provIter->ref();
+  }
+  return *this;
+}
+
+bool QgsFeatureIterator::nextFeature(QgsFeature& f)
+{
+  return provIter ? provIter->nextFeature(f) : false;
+}
+
+bool QgsFeatureIterator::rewind()
+{
+  return provIter ? provIter->rewind() : false;
+}
+
+bool QgsFeatureIterator::close()
+{
+  return provIter ? provIter->close() : false;
+}
+
+bool QgsFeatureIterator::isClosed()
+{
+  return provIter ? provIter->mClosed : true;
+}
+
+
+bool operator== (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)
+{
+  return (fi1.provIter == fi2.provIter);
+}
+bool operator!= (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)
+{
+  return !(fi1 == fi2);
+}
+
+////////////
+
 QgsVectorDataProvider::QgsVectorDataProvider( QString uri )
     : QgsDataProvider( uri ),
     mCacheMinMaxDirty( true ),
@@ -49,6 +157,11 @@
   return -1;
 }
 
+QgsFeatureIterator QgsVectorDataProvider::getFeatures( QgsAttributeList, QgsRectangle, bool, bool)
+{
+  return QgsFeatureIterator();
+}
+
 bool QgsVectorDataProvider::featureAtId( int featureId,
     QgsFeature& feature,
     bool fetchGeometry,

Modified: branches/threading-branch/src/core/qgsvectordataprovider.h
===================================================================
--- branches/threading-branch/src/core/qgsvectordataprovider.h	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/qgsvectordataprovider.h	2010-07-03 16:50:45 UTC (rev 13881)
@@ -25,10 +25,88 @@
 //QGIS Includes
 #include "qgis.h"
 #include "qgsdataprovider.h"
-#include "qgsvectorlayer.h"
+#include "qgsfeature.h"
 #include "qgsfield.h"
+#include "qgsrectangle.h"
 
+typedef QList<int> QgsAttributeList;
+typedef QSet<int> QgsFeatureIds;
+typedef QSet<int> QgsAttributeIds;
+
+
 /** \ingroup core
+ * Internal feature iterator to be implemented within data providers
+ */
+class QgsVectorDataProviderIterator
+{
+public:
+  //! base class constructor - stores the iteration parameters
+  QgsVectorDataProviderIterator(QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                QgsRectangle rect = QgsRectangle(),
+                                bool fetchGeometry = true,
+                                bool useIntersect = false );
+
+  //! destructor makes sure that the iterator is closed properly
+  virtual ~QgsVectorDataProviderIterator();
+
+  //! fetch next feature, return true on success
+  virtual bool nextFeature(QgsFeature& f) = 0;
+  //! reset the iterator to the starting position
+  virtual bool rewind() = 0;
+  //! end of iterating: free the resources / lock
+  virtual bool close() = 0;
+
+protected:
+  QgsAttributeList mFetchAttributes;
+  bool mFetchGeometry;
+  QgsRectangle mRect;
+  bool mUseIntersect;
+
+  bool mClosed;
+
+  // reference counting (to allow seamless copying of QgsFeatureIterator instances)
+  int refs;
+  void ref(); // add reference
+  void deref(); // remove reference, delete if refs == 0
+  friend class QgsFeatureIterator;
+};
+
+/**
+ * \ingroup core
+ * Wrapper for iterator of features from vector data provider or vector layer
+ */
+class QgsFeatureIterator
+{
+public:
+  //! construct invalid iterator
+  QgsFeatureIterator();
+  //! construct an iterator for iterating an instance of vector data provider
+  QgsFeatureIterator(QgsVectorDataProviderIterator* iter);
+  //! construct an iterator for iterating an instance of vector layer (data provider + uncommitted data)
+  //QgsFeatureIterator(VectorLayerIterator* layerIter);
+  //! copy constructor copies the provider iterator, increases ref.count
+  QgsFeatureIterator(const QgsFeatureIterator& fi);
+  //! destructor deletes the provider iterator if it has no more references
+  ~QgsFeatureIterator();
+
+  QgsFeatureIterator& operator=(const QgsFeatureIterator& other);
+
+  bool nextFeature(QgsFeature& f);
+  bool rewind();
+  bool close();
+
+  //! find out whether the iterator is still valid or closed already
+  bool isClosed();
+
+  friend bool operator== (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2);
+  friend bool operator!= (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2);
+
+protected:
+  QgsVectorDataProviderIterator* provIter;
+};
+
+
+/** \ingroup core
  * This is the base class for vector data providers.
  *
  * Data providers abstract the retrieval and writing (where supported)
@@ -113,6 +191,16 @@
     virtual long updateFeatureCount();
 
     /**
+     * Start iterating over features of the vector data provider.
+     * For new code, consider using this method instead of select/nextFeature combo.
+     * @note Added in v1.6
+     */
+    virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                            QgsRectangle rect = QgsRectangle(),
+                                            bool fetchGeometry = true,
+                                            bool useIntersect = false );
+
+    /**
      * Gets the feature at the given feature ID.
      * @param featureId of the feature to be returned
      * @param feature which will receive the data

Modified: branches/threading-branch/src/core/qgsvectorlayer.cpp
===================================================================
--- branches/threading-branch/src/core/qgsvectorlayer.cpp	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/qgsvectorlayer.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -67,6 +67,7 @@
 #include "qgssinglesymbolrenderer.h"
 #include "qgscoordinatereferencesystem.h"
 #include "qgsvectordataprovider.h"
+#include "qgsvectorlayeriterator.h"
 #include "qgsvectorlayerundocommand.h"
 #include "qgsvectoroverlay.h"
 #include "qgsmaplayerregistry.h"
@@ -106,8 +107,7 @@
     mUsingRendererV2( false ),
     mLabel( 0 ),
     mLabelOn( false ),
-    mVertexMarkerOnlyForSelection( false ),
-    mFetching( false )
+    mVertexMarkerOnlyForSelection( false )
 {
   mActions = new QgsAttributeAction;
 
@@ -689,7 +689,7 @@
   return ptr;
 }
 
-void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool labeling )
+void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi )
 {
   QSettings settings;
   bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
@@ -697,7 +697,7 @@
   mRendererV2->startRender( rendererContext, this );
 
   QgsFeature fet;
-  while ( nextFeature( fet ) )
+  while ( fi.nextFeature( fet ) )
   {
     try
     {
@@ -730,7 +730,7 @@
   }
 }
 
-void QgsVectorLayer::drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling )
+void QgsVectorLayer::drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi )
 {
   QHash< QgsSymbolV2*, QList<QgsFeature> > features; // key = symbol, value = array of features
 
@@ -751,7 +751,7 @@
 
   // 1. fetch features
   QgsFeature fet;
-  while ( nextFeature( fet ) )
+  while ( fi.nextFeature( fet ) )
   {
     if ( rendererContext.renderingStopped() )
     {
@@ -872,13 +872,15 @@
       }
     }
 
-    select( attributes, rendererContext.extent() );
+    QgsFeatureIterator fi = getFeatures( attributes, rendererContext.extent() );
 
     if ( mRendererV2->usingSymbolLevels() )
-      drawRendererV2Levels( rendererContext, labeling );
+      drawRendererV2Levels( rendererContext, labeling, fi );
     else
-      drawRendererV2( rendererContext, labeling );
+      drawRendererV2( rendererContext, labeling, fi );
 
+    fi.close();
+
     return true;
   }
 
@@ -929,11 +931,11 @@
       }
     }
 
-    select( attributes, rendererContext.extent() );
+    QgsFeatureIterator fi = getFeatures( attributes, rendererContext.extent() );
 
     try
     {
-      while ( nextFeature( fet ) )
+      while ( fi.nextFeature( fet ) )
       {
 
         if ( rendererContext.renderingStopped() )
@@ -1360,7 +1362,7 @@
   return res;
 }
 
-void QgsVectorLayer::updateFeatureAttributes( QgsFeature &f, bool all )
+void QgsVectorLayer::updateFeatureAttributes( QgsFeature &f, const QgsAttributeList& fetchAttributes )
 {
   // do not update when we aren't in editing mode
   if ( !mEditable )
@@ -1381,7 +1383,7 @@
 
   // null/add all attributes that were added, but don't exist in the feature yet
   for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ )
-    if ( !map.contains( it.key() ) && ( all || mFetchAttributes.contains( it.key() ) ) )
+    if ( !map.contains( it.key() ) && fetchAttributes.contains( it.key() ) )
       f.changeAttribute( it.key(), QVariant( QString::null ) );
 }
 
@@ -1394,165 +1396,25 @@
 
 void QgsVectorLayer::select( QgsAttributeList attributes, QgsRectangle rect, bool fetchGeometries, bool useIntersect )
 {
-  if ( !mDataProvider )
-    return;
-
-  mFetching        = true;
-  mFetchRect       = rect;
-  mFetchAttributes = attributes;
-  mFetchGeometry   = fetchGeometries;
-
-  mFetchConsidered = mDeletedFeatureIds;
-
-  if ( mEditable )
-  {
-    mFetchAddedFeaturesIt = mAddedFeatures.begin();
-    mFetchChangedGeomIt = mChangedGeometries.begin();
-  }
-
-  //look in the normal features of the provider
-  if ( mFetchAttributes.size() > 0 )
-  {
-    if ( mEditable )
-    {
-      // fetch only available field from provider
-      mFetchProvAttributes.clear();
-      for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); it++ )
-      {
-        if ( !mUpdatedFields.contains( *it ) || mAddedAttributeIds.contains( *it ) )
-          continue;
-
-        mFetchProvAttributes << *it;
-      }
-
-      mDataProvider->select( mFetchProvAttributes, rect, fetchGeometries, useIntersect );
-    }
-    else
-      mDataProvider->select( mFetchAttributes, rect, fetchGeometries, useIntersect );
-  }
-  else
-  {
-    mDataProvider->select( QgsAttributeList(), rect, fetchGeometries, useIntersect );
-  }
+  if (!mOldApiIter.isClosed())
+    mOldApiIter.close();
+  mOldApiIter = getFeatures( attributes, rect, fetchGeometries, useIntersect );
 }
 
 bool QgsVectorLayer::nextFeature( QgsFeature &f )
 {
-  if ( !mFetching )
-    return false;
+  return mOldApiIter.nextFeature(f);
+}
 
-  if ( mEditable )
-  {
-    if ( !mFetchRect.isEmpty() )
-    {
-      // check if changed geometries are in rectangle
-      for ( ; mFetchChangedGeomIt != mChangedGeometries.end(); mFetchChangedGeomIt++ )
-      {
-        int fid = mFetchChangedGeomIt.key();
-
-        if ( mFetchConsidered.contains( fid ) )
-          // skip deleted features
-          continue;
-
-        mFetchConsidered << fid;
-
-        if ( !mFetchChangedGeomIt->intersects( mFetchRect ) )
-          // skip changed geometries not in rectangle and don't check again
-          continue;
-
-        f.setFeatureId( fid );
-        f.setValid( true );
-
-        if ( mFetchGeometry )
-          f.setGeometry( mFetchChangedGeomIt.value() );
-
-        if ( mFetchAttributes.size() > 0 )
-        {
-          if ( fid < 0 )
-          {
-            // fid<0 => in mAddedFeatures
-            bool found = false;
-
-            for ( QgsFeatureList::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); it++ )
-            {
-              if ( fid != it->id() )
-              {
-                found = true;
-                f.setAttributeMap( it->attributeMap() );
-                break;
-              }
-            }
-
-            if ( !found )
-              QgsDebugMsg( QString( "No attributes for the added feature %1 found" ).arg( f.id() ) );
-          }
-          else
-          {
-            // retrieve attributes from provider
-            QgsFeature tmp;
-            mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
-            updateFeatureAttributes( tmp );
-            f.setAttributeMap( tmp.attributeMap() );
-          }
-        }
-
-        // return complete feature
-        mFetchChangedGeomIt++;
-        return true;
-      }
-
-      // no more changed geometries
-    }
-
-    for ( ; mFetchAddedFeaturesIt != mAddedFeatures.end(); mFetchAddedFeaturesIt++ )
-    {
-      int fid = mFetchAddedFeaturesIt->id();
-
-      if ( mFetchConsidered.contains( fid ) )
-        // must have changed geometry outside rectangle
-        continue;
-
-      if ( !mFetchRect.isEmpty() &&
-           mFetchAddedFeaturesIt->geometry() &&
-           !mFetchAddedFeaturesIt->geometry()->intersects( mFetchRect ) )
-        // skip added features not in rectangle
-        continue;
-
-      f.setFeatureId( fid );
-      f.setValid( true );
-
-      if ( mFetchGeometry )
-        f.setGeometry( *mFetchAddedFeaturesIt->geometry() );
-
-      if ( mFetchAttributes.size() > 0 )
-      {
-        f.setAttributeMap( mFetchAddedFeaturesIt->attributeMap() );
-        updateFeatureAttributes( f );
-      }
-
-      mFetchAddedFeaturesIt++;
-      return true;
-    }
-
-    // no more added features
-  }
-
-  while ( dataProvider()->nextFeature( f ) )
-  {
-    if ( mFetchConsidered.contains( f.id() ) )
-      continue;
-
-    if ( mEditable )
-      updateFeatureAttributes( f );
-
-    // found it
-    return true;
-  }
-
-  mFetching = false;
-  return false;
+QgsFeatureIterator QgsVectorLayer::getFeatures( QgsAttributeList fetchAttributes,
+                                                QgsRectangle rect,
+                                                bool fetchGeometry,
+                                                bool useIntersect )
+{
+  return QgsFeatureIterator( new QgsVectorLayerIterator( this, fetchAttributes, rect, fetchGeometry, useIntersect ) );
 }
 
+
 bool QgsVectorLayer::featureAtId( int featureId, QgsFeature& f, bool fetchGeometries, bool fetchAttributes )
 {
   if ( !mDataProvider )
@@ -1594,7 +1456,7 @@
         mDataProvider->featureAtId( featureId, tmp, false, mDataProvider->attributeIndexes() );
         f.setAttributeMap( tmp.attributeMap() );
       }
-      updateFeatureAttributes( f, true );
+      updateFeatureAttributes( f, pendingAllAttributesList() );
     }
     return true;
   }
@@ -1621,7 +1483,7 @@
   {
     if ( mDataProvider->featureAtId( featureId, f, fetchGeometries, mDataProvider->attributeIndexes() ) )
     {
-      updateFeatureAttributes( f, true );
+      updateFeatureAttributes( f, pendingAllAttributesList() );
       return true;
     }
   }
@@ -3444,6 +3306,7 @@
   QgsFeatureList features;
 
   QgsAttributeList allAttrs = mDataProvider->attributeIndexes();
+  QgsAttributeList pendingAllAttrs = pendingAllAttributesList();
 
   for ( QgsFeatureIds::iterator it = mSelectedFeatureIds.begin(); it != mSelectedFeatureIds.end(); ++it )
   {
@@ -3468,7 +3331,7 @@
       mDataProvider->featureAtId( *it, feat, true, allAttrs );
     }
 
-    updateFeatureAttributes( feat );
+    updateFeatureAttributes( feat, pendingAllAttrs );
     updateFeatureGeometry( feat );
 
     features << feat;

Modified: branches/threading-branch/src/core/qgsvectorlayer.h
===================================================================
--- branches/threading-branch/src/core/qgsvectorlayer.h	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/qgsvectorlayer.h	2010-07-03 16:50:45 UTC (rev 13881)
@@ -30,11 +30,14 @@
 #include "qgssnapper.h"
 #include "qgsfield.h"
 
+#include "qgsvectordataprovider.h"
+
 class QPainter;
 class QImage;
 
 class QgsAttributeAction;
 class QgsCoordinateTransform;
+class QgsFeatureIterator;
 class QgsGeometry;
 class QgsGeometryVertexIndex;
 class QgsMapToPixel;
@@ -50,11 +53,7 @@
 
 class QgsFeatureRendererV2;
 
-typedef QList<int> QgsAttributeList;
-typedef QSet<int> QgsFeatureIds;
-typedef QSet<int> QgsAttributeIds;
 
-
 /** \ingroup core
  * Vector layer backed by a data source provider.
  */
@@ -180,9 +179,9 @@
     void setUsingRendererV2( bool usingRendererV2 );
 
     /** Draw layer with renderer V2. Added in QGIS 1.4 */
-    void drawRendererV2( QgsRenderContext& rendererContext, bool labeling );
+    void drawRendererV2( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi );
     /** Draw layer with renderer V2 using symbol levels. Added in QGIS 1.4 */
-    void drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling );
+    void drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi );
 
     /** Returns point, line or polygon */
     QGis::GeometryType geometryType() const;
@@ -255,6 +254,16 @@
 
     bool nextFeature( QgsFeature& feature );
 
+    /**
+     * Start iterating over features of the layer.
+     * For new code, consider using this method instead of select/nextFeature combo.
+     * @note Added in v1.6
+     */
+    QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                    QgsRectangle rect = QgsRectangle(),
+                                    bool fetchGeometry = true,
+                                    bool useIntersect = false );
+
     /**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
      @return true in case of success*/
     bool featureAtId( int featureId, QgsFeature &f, bool fetchGeometries = true, bool fetchAttributes = true );
@@ -652,7 +661,7 @@
     static int currentVertexMarkerSize();
 
     /**Update feature with uncommited attribute updates*/
-    void updateFeatureAttributes( QgsFeature &f, bool all = false );
+    void updateFeatureAttributes( QgsFeature &f, const QgsAttributeList& fetchAttributes );
 
     /**Update feature with uncommited geometry updates*/
     void updateFeatureGeometry( QgsFeature &f );
@@ -779,15 +788,9 @@
     //annotation form for this layer
     QString mAnnotationForm;
 
-    bool mFetching;
-    QgsRectangle mFetchRect;
-    QgsAttributeList mFetchAttributes;
-    QgsAttributeList mFetchProvAttributes;
-    bool mFetchGeometry;
+    QgsFeatureIterator mOldApiIter;
+    friend class QgsVectorLayerIterator;
 
-    QSet<int> mFetchConsidered;
-    QgsGeometryMap::iterator mFetchChangedGeomIt;
-    QgsFeatureList::iterator mFetchAddedFeaturesIt;
 };
 
 #endif

Added: branches/threading-branch/src/core/qgsvectorlayeriterator.cpp
===================================================================
--- branches/threading-branch/src/core/qgsvectorlayeriterator.cpp	                        (rev 0)
+++ branches/threading-branch/src/core/qgsvectorlayeriterator.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,210 @@
+#include "qgsvectorlayeriterator.h"
+
+#include "qgsvectorlayer.h"
+
+#include "qgsgeometry.h"
+#include "qgslogger.h"
+
+// used from QgsVectorLayer:
+// - mDataProvider
+// - mEditable
+// - mDeletedFeatureIds
+// - mAddedFeatures
+// - mChangedGeometries
+// - mUpdatedFields
+// - mAddedAttributeIds
+// - updateFeatureAttributes()
+
+QgsVectorLayerIterator::QgsVectorLayerIterator( QgsVectorLayer* l,
+                                                QgsAttributeList fetchAttributes,
+                                                QgsRectangle rect,
+                                                bool fetchGeometry,
+                                                bool useIntersect )
+: QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect),
+  L(l)
+{
+
+  if ( !L->mDataProvider )
+  {
+    mClosed = true;
+    return;
+  }
+
+  mFetchConsidered = L->mDeletedFeatureIds;
+
+  if ( L->mEditable )
+  {
+    mFetchAddedFeaturesIt = L->mAddedFeatures.begin();
+    mFetchChangedGeomIt = L->mChangedGeometries.begin();
+  }
+
+  //look in the normal features of the provider
+  if ( mFetchAttributes.size() > 0 )
+  {
+    if ( L->mEditable )
+    {
+      // fetch only available field from provider
+      mFetchProvAttributes.clear();
+      for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); it++ )
+      {
+        if ( !L->mUpdatedFields.contains( *it ) || L->mAddedAttributeIds.contains( *it ) )
+          continue;
+
+        mFetchProvAttributes << *it;
+      }
+
+      mProvIter = L->mDataProvider->getFeatures( mFetchProvAttributes, rect, fetchGeometry, useIntersect );
+    }
+    else
+      mProvIter = L->mDataProvider->getFeatures( mFetchAttributes, rect, fetchGeometry, useIntersect );
+  }
+  else
+  {
+    mProvIter = L->mDataProvider->getFeatures( QgsAttributeList(), rect, fetchGeometry, useIntersect );
+  }
+
+}
+
+QgsVectorLayerIterator::~QgsVectorLayerIterator()
+{
+  close();
+}
+
+
+bool QgsVectorLayerIterator::nextFeature(QgsFeature& f)
+{
+  if ( mClosed )
+    return false;
+
+  if ( L->mEditable )
+  {
+    if ( !mRect.isEmpty() )
+    {
+      // check if changed geometries are in rectangle
+      for ( ; mFetchChangedGeomIt != L->mChangedGeometries.end(); mFetchChangedGeomIt++ )
+      {
+        int fid = mFetchChangedGeomIt.key();
+
+        if ( mFetchConsidered.contains( fid ) )
+          // skip deleted features
+          continue;
+
+        mFetchConsidered << fid;
+
+        if ( !mFetchChangedGeomIt->intersects( mRect ) )
+          // skip changed geometries not in rectangle and don't check again
+          continue;
+
+        f.setFeatureId( fid );
+        f.setValid( true );
+
+        if ( mFetchGeometry )
+          f.setGeometry( mFetchChangedGeomIt.value() );
+
+        if ( mFetchAttributes.size() > 0 )
+        {
+          if ( fid < 0 )
+          {
+            // fid<0 => in mAddedFeatures
+            bool found = false;
+
+            for ( QgsFeatureList::iterator it = L->mAddedFeatures.begin(); it != L->mAddedFeatures.end(); it++ )
+            {
+              if ( fid != it->id() )
+              {
+                found = true;
+                f.setAttributeMap( it->attributeMap() );
+                break;
+              }
+            }
+
+            if ( !found )
+              QgsDebugMsg( QString( "No attributes for the added feature %1 found" ).arg( f.id() ) );
+          }
+          else
+          {
+            // retrieve attributes from provider
+            QgsFeature tmp;
+            // TODO: do not fetch here using featureAtId - do it when iterating in provider
+            L->mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
+            L->updateFeatureAttributes( tmp, mFetchAttributes );
+            f.setAttributeMap( tmp.attributeMap() );
+          }
+        }
+
+        // return complete feature
+        mFetchChangedGeomIt++;
+        return true;
+      }
+
+      // no more changed geometries
+    }
+
+    for ( ; mFetchAddedFeaturesIt != L->mAddedFeatures.end(); mFetchAddedFeaturesIt++ )
+    {
+      int fid = mFetchAddedFeaturesIt->id();
+
+      if ( mFetchConsidered.contains( fid ) )
+        // must have changed geometry outside rectangle
+        continue;
+
+      if ( !mRect.isEmpty() &&
+           mFetchAddedFeaturesIt->geometry() &&
+           !mFetchAddedFeaturesIt->geometry()->intersects( mRect ) )
+        // skip added features not in rectangle
+        continue;
+
+      f.setFeatureId( fid );
+      f.setValid( true );
+
+      if ( mFetchGeometry )
+        f.setGeometry( *mFetchAddedFeaturesIt->geometry() );
+
+      if ( mFetchAttributes.size() > 0 )
+      {
+        f.setAttributeMap( mFetchAddedFeaturesIt->attributeMap() );
+        L->updateFeatureAttributes( f, mFetchAttributes );
+      }
+
+      mFetchAddedFeaturesIt++;
+      return true;
+    }
+
+    // no more added features
+  }
+
+  while ( mProvIter.nextFeature( f ) )
+  {
+    if ( mFetchConsidered.contains( f.id() ) )
+      continue;
+
+    if ( L->mEditable )
+      L->updateFeatureAttributes( f, mFetchAttributes );
+
+    // found it
+    return true;
+  }
+
+  close();
+  return false;
+}
+
+bool QgsVectorLayerIterator::rewind()
+{
+  if (mClosed)
+    return false;
+
+  // TODO: rewind editing stuff
+  mProvIter.rewind();
+  return false;
+}
+
+bool QgsVectorLayerIterator::close()
+{
+  if (mClosed)
+    return false;
+
+  mProvIter.close();
+  mClosed = true;
+  return true;
+}

Added: branches/threading-branch/src/core/qgsvectorlayeriterator.h
===================================================================
--- branches/threading-branch/src/core/qgsvectorlayeriterator.h	                        (rev 0)
+++ branches/threading-branch/src/core/qgsvectorlayeriterator.h	2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,41 @@
+#ifndef QGSVECTORLAYERITERATOR_H
+#define QGSVECTORLAYERITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+class QgsVectorLayer;
+
+class QgsVectorLayerIterator : public QgsVectorDataProviderIterator
+{
+public:
+
+  QgsVectorLayerIterator( QgsVectorLayer* l,
+                          QgsAttributeList fetchAttributes,
+                          QgsRectangle rect,
+                          bool fetchGeometry,
+                          bool useIntersect );
+
+  ~QgsVectorLayerIterator();
+
+  //! fetch next feature, return true on success
+  virtual bool nextFeature(QgsFeature& f);
+
+  //! reset the iterator to the starting position
+  virtual bool rewind();
+
+  //! end of iterating: free the resources / lock
+  virtual bool close();
+
+protected:
+  QgsVectorLayer* L;
+
+  QgsAttributeList mFetchProvAttributes;
+  QgsFeatureIterator mProvIter;
+
+  QSet<int> mFetchConsidered;
+  QgsGeometryMap::iterator mFetchChangedGeomIt;
+  QgsFeatureList::iterator mFetchAddedFeaturesIt;
+
+};
+
+#endif // QGSVECTORLAYERITERATOR_H

Modified: branches/threading-branch/src/gui/qgsmaptip.cpp
===================================================================
--- branches/threading-branch/src/gui/qgsmaptip.cpp	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/gui/qgsmaptip.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -15,7 +15,7 @@
 // QGIS includes
 #include <qgsmapcanvas.h>
 #include <qgsmaplayer.h>
-#include <qgsvectordataprovider.h>
+#include <qgsvectorlayer.h>
 #include <qgsfield.h>
 
 // Qt includes

Modified: branches/threading-branch/src/providers/ogr/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/providers/ogr/CMakeLists.txt	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/ogr/CMakeLists.txt	2010-07-03 16:50:45 UTC (rev 13881)
@@ -1,5 +1,5 @@
 
-SET (OGR_SRCS qgsogrprovider.cpp)
+SET (OGR_SRCS qgsogrprovider.cpp qgsogrfeatureiterator.cpp)
 
 SET(OGR_MOC_HDRS qgsogrprovider.h)
 

Added: branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.cpp
===================================================================
--- branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.cpp	                        (rev 0)
+++ branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,189 @@
+#include "qgsogrfeatureiterator.h"
+
+#include "qgsogrprovider.h"
+
+#include "qgsapplication.h"
+#include "qgslogger.h"
+#include "qgsgeometry.h"
+
+// P:
+// - ogrLayer
+// - mFetchFeaturesWithoutGeom
+// - getFeatureAttribute()
+
+QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrProvider* p,
+                                              QgsAttributeList fetchAttributes,
+                                              QgsRectangle rect,
+                                              bool fetchGeometry,
+                                              bool useIntersect )
+ : QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect),
+   P(p)
+{
+  // first of all, lock the OGR layer!
+  QgsDebugMsg("trying to lock OGR layer");
+  P->mLayerMutex.lock();
+
+  // set the selection rectangle pointer to 0
+  mSelectionRectangle = 0;
+
+
+  // spatial query to select features
+  if ( rect.isEmpty() )
+  {
+    OGR_L_SetSpatialFilter( P->ogrLayer, 0 );
+  }
+  else
+  {
+    OGRGeometryH filter = 0;
+    QString wktExtent = QString( "POLYGON((%1))" ).arg( rect.asPolygon() );
+    QByteArray ba = wktExtent.toAscii();
+    const char *wktText = ba;
+
+    if ( useIntersect )
+    {
+      // store the selection rectangle for use in filtering features during
+      // an identify and display attributes
+      if ( mSelectionRectangle )
+        OGR_G_DestroyGeometry( mSelectionRectangle );
+
+      OGR_G_CreateFromWkt(( char ** )&wktText, NULL, &mSelectionRectangle );
+      wktText = ba;
+    }
+
+    OGR_G_CreateFromWkt(( char ** )&wktText, NULL, &filter );
+    QgsDebugMsg( "Setting spatial filter using " + wktExtent );
+    OGR_L_SetSpatialFilter( P->ogrLayer, filter );
+    OGR_G_DestroyGeometry( filter );
+  }
+
+  //start with first feature
+  OGR_L_ResetReading( P->ogrLayer );
+
+}
+
+QgsOgrFeatureIterator::~QgsOgrFeatureIterator()
+{
+  close();
+}
+
+
+bool QgsOgrFeatureIterator::nextFeature(QgsFeature& feature)
+{
+
+  feature.setValid( false );
+
+  OGRFeatureH fet;
+  QgsRectangle selectionRect;
+
+  while (( fet = OGR_L_GetNextFeature( P->ogrLayer ) ) != NULL )
+  {
+    // skip features without geometry
+    if ( !P->mFetchFeaturesWithoutGeom && OGR_F_GetGeometryRef( fet ) == NULL )
+    {
+      OGR_F_Destroy( fet );
+      continue;
+    }
+
+    OGRFeatureDefnH featureDefinition = OGR_F_GetDefnRef( fet );
+    QString featureTypeName = featureDefinition ? QString( OGR_FD_GetName( featureDefinition ) ) : QString( "" );
+    feature.setFeatureId( OGR_F_GetFID( fet ) );
+    feature.clearAttributeMap();
+    feature.setTypeName( featureTypeName );
+
+    /* fetch geometry */
+    if ( mFetchGeometry || mUseIntersect )
+    {
+      OGRGeometryH geom = OGR_F_GetGeometryRef( fet );
+
+      if ( geom == 0 )
+      {
+        OGR_F_Destroy( fet );
+        continue;
+      }
+
+      // get the wkb representation
+      unsigned char *wkb = new unsigned char[OGR_G_WkbSize( geom )];
+      OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
+
+      feature.setGeometryAndOwnership( wkb, OGR_G_WkbSize( geom ) );
+
+      if ( mUseIntersect )
+      {
+        //precise test for intersection with search rectangle
+        //first make QgsRectangle from OGRPolygon
+        OGREnvelope env;
+        memset( &env, 0, sizeof( env ) );
+        if ( mSelectionRectangle )
+          OGR_G_GetEnvelope( mSelectionRectangle, &env );
+        if ( env.MinX != 0 || env.MinY != 0 || env.MaxX != 0 || env.MaxY != 0 ) //if envelope is invalid, skip the precise intersection test
+        {
+          selectionRect.set( env.MinX, env.MinY, env.MaxX, env.MaxY );
+          if ( !feature.geometry()->intersects( selectionRect ) )
+          {
+            OGR_F_Destroy( fet );
+            continue;
+          }
+        }
+
+      }
+    }
+
+    /* fetch attributes */
+    for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); ++it )
+    {
+      P->getFeatureAttribute( fet, feature, *it );
+    }
+
+    /* we have a feature, end this cycle */
+    break;
+
+  } /* while */
+
+  if ( fet )
+  {
+    if ( OGR_F_GetGeometryRef( fet ) != NULL )
+    {
+      feature.setValid( true );
+    }
+    else
+    {
+      feature.setValid( false );
+    }
+    OGR_F_Destroy( fet );
+    return true;
+  }
+  else
+  {
+    QgsDebugMsg( "Feature is null" );
+    // probably should reset reading here
+    OGR_L_ResetReading( P->ogrLayer );
+    return false;
+  }
+
+}
+
+bool QgsOgrFeatureIterator::rewind()
+{
+  OGR_L_ResetReading( P->ogrLayer );
+
+  return true;
+}
+
+bool QgsOgrFeatureIterator::close()
+{
+  if (mClosed)
+    return false;
+
+  if ( mSelectionRectangle )
+  {
+    OGR_G_DestroyGeometry( mSelectionRectangle );
+    mSelectionRectangle = 0;
+  }
+
+  // we're done - unlock the mutex
+  QgsDebugMsg("unlocking OGR layer");
+  P->mLayerMutex.unlock();
+
+  mClosed = true;
+  return true;
+}

Added: branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.h
===================================================================
--- branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.h	                        (rev 0)
+++ branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.h	2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,37 @@
+#ifndef QGSOGRFEATUREITERATOR_H
+#define QGSOGRFEATUREITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+class QgsOgrProvider;
+
+#include <ogr_api.h>
+
+class QgsOgrFeatureIterator : public QgsVectorDataProviderIterator
+{
+public:
+  QgsOgrFeatureIterator( QgsOgrProvider* p,
+                         QgsAttributeList fetchAttributes,
+                         QgsRectangle rect,
+                         bool fetchGeometry,
+                         bool useIntersect );
+
+  ~QgsOgrFeatureIterator();
+
+  //! fetch next feature, return true on success
+  virtual bool nextFeature(QgsFeature& f);
+
+  //! reset the iterator to the starting position
+  virtual bool rewind();
+
+  //! end of iterating: free the resources / lock
+  virtual bool close();
+
+protected:
+  QgsOgrProvider* P;
+
+  //! Selection rectangle
+  OGRGeometryH mSelectionRectangle;
+};
+
+#endif // QGSOGRFEATUREITERATOR_H

Modified: branches/threading-branch/src/providers/ogr/qgsogrprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/ogr/qgsogrprovider.cpp	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/ogr/qgsogrprovider.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -87,8 +87,6 @@
 
   QgsApplication::registerOgrDrivers();
 
-  // set the selection rectangle pointer to 0
-  mSelectionRectangle = 0;
   // make connection to the data source
 
   QgsDebugMsg( "Data source uri is " + uri );
@@ -213,11 +211,6 @@
     extent_ = 0;
   }
 
-  if ( mSelectionRectangle )
-  {
-    OGR_G_DestroyGeometry( mSelectionRectangle );
-    mSelectionRectangle = 0;
-  }
 }
 
 bool QgsOgrProvider::setSubsetString( QString theSQL )
@@ -403,12 +396,31 @@
   return ogrDriverName;
 }
 
+#include "qgsogrfeatureiterator.h"
 
+QgsFeatureIterator QgsOgrProvider::getFeatures( QgsAttributeList fetchAttributes,
+                                                QgsRectangle rect,
+                                                bool fetchGeometry,
+                                                bool useIntersect )
+{
+  if ( !valid )
+  {
+    QgsDebugMsg( "Read attempt on an invalid OGR layer" );
+    return QgsFeatureIterator();
+  }
+
+  return QgsFeatureIterator( new QgsOgrFeatureIterator(this, fetchAttributes, rect, fetchGeometry, useIntersect) );
+}
+
+
 bool QgsOgrProvider::featureAtId( int featureId,
                                   QgsFeature& feature,
                                   bool fetchGeometry,
                                   QgsAttributeList fetchAttributes )
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   OGRFeatureH fet = OGR_L_GetFeature( ogrLayer, featureId );
   if ( fet == NULL )
     return false;
@@ -456,140 +468,27 @@
 
 bool QgsOgrProvider::nextFeature( QgsFeature& feature )
 {
-  feature.setValid( false );
-
-  if ( !valid )
-  {
-    QgsLogger::warning( "Read attempt on an invalid shapefile data source" );
-    return false;
-  }
-
-  OGRFeatureH fet;
-  QgsRectangle selectionRect;
-
-  while (( fet = OGR_L_GetNextFeature( ogrLayer ) ) != NULL )
-  {
-    // skip features without geometry
-    if ( !mFetchFeaturesWithoutGeom && OGR_F_GetGeometryRef( fet ) == NULL )
-    {
-      OGR_F_Destroy( fet );
-      continue;
-    }
-
-    OGRFeatureDefnH featureDefinition = OGR_F_GetDefnRef( fet );
-    QString featureTypeName = featureDefinition ? QString( OGR_FD_GetName( featureDefinition ) ) : QString( "" );
-    feature.setFeatureId( OGR_F_GetFID( fet ) );
-    feature.clearAttributeMap();
-    feature.setTypeName( featureTypeName );
-
-    /* fetch geometry */
-    if ( mFetchGeom || mUseIntersect )
-    {
-      OGRGeometryH geom = OGR_F_GetGeometryRef( fet );
-
-      if ( geom == 0 )
-      {
-        OGR_F_Destroy( fet );
-        continue;
-      }
-
-      // get the wkb representation
-      unsigned char *wkb = new unsigned char[OGR_G_WkbSize( geom )];
-      OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
-
-      feature.setGeometryAndOwnership( wkb, OGR_G_WkbSize( geom ) );
-
-      if ( mUseIntersect )
-      {
-        //precise test for intersection with search rectangle
-        //first make QgsRectangle from OGRPolygon
-        OGREnvelope env;
-        memset( &env, 0, sizeof( env ) );
-        if ( mSelectionRectangle )
-          OGR_G_GetEnvelope( mSelectionRectangle, &env );
-        if ( env.MinX != 0 || env.MinY != 0 || env.MaxX != 0 || env.MaxY != 0 ) //if envelope is invalid, skip the precise intersection test
-        {
-          selectionRect.set( env.MinX, env.MinY, env.MaxX, env.MaxY );
-          if ( !feature.geometry()->intersects( selectionRect ) )
-          {
-            OGR_F_Destroy( fet );
-            continue;
-          }
-        }
-
-      }
-    }
-
-    /* fetch attributes */
-    for ( QgsAttributeList::iterator it = mAttributesToFetch.begin(); it != mAttributesToFetch.end(); ++it )
-    {
-      getFeatureAttribute( fet, feature, *it );
-    }
-
-    /* we have a feature, end this cycle */
-    break;
-
-  } /* while */
-
-  if ( fet )
-  {
-    if ( OGR_F_GetGeometryRef( fet ) != NULL )
-    {
-      feature.setValid( true );
-    }
-    else
-    {
-      feature.setValid( false );
-    }
-    OGR_F_Destroy( fet );
+  if (mOldApiIter.nextFeature(feature))
     return true;
-  }
   else
   {
-    QgsDebugMsg( "Feature is null" );
-    // probably should reset reading here
-    OGR_L_ResetReading( ogrLayer );
+    mOldApiIter.close(); // make sure to unlock the layer
     return false;
   }
 }
+#include <QThread>
 
 void QgsOgrProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
 {
-  mUseIntersect = useIntersect;
-  mAttributesToFetch = fetchAttributes;
-  mFetchGeom = fetchGeometry;
-
-  // spatial query to select features
-  if ( rect.isEmpty() )
+  if (qApp->thread() != QThread::currentThread())
   {
-    OGR_L_SetSpatialFilter( ogrLayer, 0 );
+    QgsDebugMsg("accessing old provider API from non-gui thread! (IGNORING)");
+    return;
   }
-  else
-  {
-    OGRGeometryH filter = 0;
-    QString wktExtent = QString( "POLYGON((%1))" ).arg( rect.asPolygon() );
-    QByteArray ba = wktExtent.toAscii();
-    const char *wktText = ba;
 
-    if ( useIntersect )
-    {
-      // store the selection rectangle for use in filtering features during
-      // an identify and display attributes
-      if ( mSelectionRectangle )
-        OGR_G_DestroyGeometry( mSelectionRectangle );
-
-      OGR_G_CreateFromWkt(( char ** )&wktText, NULL, &mSelectionRectangle );
-      wktText = ba;
-    }
-
-    OGR_G_CreateFromWkt(( char ** )&wktText, NULL, &filter );
-    QgsDebugMsg( "Setting spatial filter using " + wktExtent );
-    OGR_L_SetSpatialFilter( ogrLayer, filter );
-    OGR_G_DestroyGeometry( filter );
-  }
-
-  //start with first feature
-  OGR_L_ResetReading( ogrLayer );
+  //if (mOldApiIter != QgsFeatureIterator())
+  mOldApiIter.close();
+  mOldApiIter = getFeatures( fetchAttributes, rect, fetchGeometry, useIntersect );
 }
 
 
@@ -613,6 +512,9 @@
 {
   if ( !extent_ )
   {
+    // make sure no other thread is accessing the layer right now
+    QMutexLocker layerLocker(&mLayerMutex);
+
     extent_ = calloc( sizeof( OGREnvelope ), 1 );
 
     // get the extent_ (envelope) of the layer
@@ -732,7 +634,9 @@
 
 void QgsOgrProvider::rewind()
 {
-  OGR_L_ResetReading( ogrLayer );
+  // the iterator is closed everyt
+  //mOldApiIter = getFeatures( fetchAttributes, rect, fetchGeometry, useIntersect );
+  mOldApiIter.rewind();
 }
 
 
@@ -746,6 +650,9 @@
 
 bool QgsOgrProvider::addFeature( QgsFeature& f )
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   bool returnValue = true;
   OGRFeatureDefnH fdef = OGR_L_GetLayerDefn( ogrLayer );
   OGRFeatureH feature = OGR_F_Create( fdef );
@@ -848,6 +755,9 @@
 
 bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   bool returnvalue = true;
 
   for ( QList<QgsField>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter )
@@ -888,6 +798,9 @@
 
 bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
   {
     long fid = ( long ) it.key();
@@ -953,6 +866,9 @@
 
 bool QgsOgrProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   OGRErr res;
   OGRFeatureH theOGRFeature = 0;
   OGRGeometryH theNewGeometry = 0;
@@ -1060,6 +976,9 @@
 
 bool QgsOgrProvider::deleteFeature( int id )
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   return OGR_L_DeleteFeature( ogrLayer, id ) == OGRERR_NONE;
 }
 
@@ -1784,6 +1703,9 @@
 
 void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit )
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   QgsField fld = mAttributeFields[index];
   QString theLayerName = OGR_FD_GetName( OGR_L_GetLayerDefn( ogrLayer ) );
 
@@ -1820,6 +1742,9 @@
 
 QVariant QgsOgrProvider::minimumValue( int index )
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   QgsField fld = mAttributeFields[index];
   QString theLayerName = OGR_FD_GetName( OGR_L_GetLayerDefn( ogrLayer ) );
 
@@ -1854,6 +1779,9 @@
 
 QVariant QgsOgrProvider::maximumValue( int index )
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   QgsField fld = mAttributeFields[index];
   QString theLayerName = OGR_FD_GetName( OGR_L_GetLayerDefn( ogrLayer ) );
 
@@ -1895,6 +1823,9 @@
 
 bool QgsOgrProvider::syncToDisc()
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   OGR_L_SyncToDisk( ogrLayer );
 
   //for shapefiles: is there already a spatial index?
@@ -1923,6 +1854,9 @@
 
 void QgsOgrProvider::recalculateFeatureCount()
 {
+  // make sure no other thread is accessing the layer right now
+  QMutexLocker layerLocker(&mLayerMutex);
+
   OGRGeometryH filter = OGR_L_GetSpatialFilter( ogrLayer );
   if ( filter )
   {

Modified: branches/threading-branch/src/providers/ogr/qgsogrprovider.h
===================================================================
--- branches/threading-branch/src/providers/ogr/qgsogrprovider.h	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/ogr/qgsogrprovider.h	2010-07-03 16:50:45 UTC (rev 13881)
@@ -24,6 +24,8 @@
 
 #include <ogr_api.h>
 
+#include <QMutex>
+
 /**
   \class QgsOgrProvider
   \brief Data provider for ESRI shapefiles
@@ -79,6 +81,12 @@
      */
     virtual bool nextFeature( QgsFeature& feature );
 
+
+    virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                            QgsRectangle rect = QgsRectangle(),
+                                            bool fetchGeometry = true,
+                                            bool useIntersect = false );
+
     /**
      * Gets the feature at the given feature ID.
      * @param featureId id of the feature
@@ -279,13 +287,12 @@
     QString ogrDriverName;
 
     bool valid;
-    //! Flag to indicate that spatial intersect should be used in selecting features
-    bool mUseIntersect;
     int geomType;
     long featuresCounted;
 
-    //! Selection rectangle
-    OGRGeometryH mSelectionRectangle;
+    QgsFeatureIterator mOldApiIter;
+    friend class QgsOgrFeatureIterator;
+
     /**Adds one feature*/
     bool addFeature( QgsFeature& f );
     /**Deletes one feature*/
@@ -295,4 +302,6 @@
 
     /**Calls OGR_L_SyncToDisk and recreates the spatial index if present*/
     bool syncToDisc();
+
+    QMutex mLayerMutex;
 };

Modified: branches/threading-branch/src/providers/osm/osmprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/osm/osmprovider.cpp	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/osm/osmprovider.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -22,6 +22,7 @@
 #include "qgslogger.h"
 #include "qgsvectordataprovider.h"
 #include "qgsapplication.h"
+#include "qgsvectorlayer.h"
 
 #include <QFileInfo>
 #include <QDateTime>

Modified: branches/threading-branch/src/providers/postgres/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/providers/postgres/CMakeLists.txt	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/postgres/CMakeLists.txt	2010-07-03 16:50:45 UTC (rev 13881)
@@ -2,7 +2,7 @@
 ########################################################
 # Files
 
-SET(PG_SRCS qgspostgresprovider.cpp)
+SET(PG_SRCS qgspostgresprovider.cpp qgspostgresfeatureiterator.cpp)
 SET(PG_MOC_HDRS qgspostgresprovider.h)
 
 

Added: branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.cpp
===================================================================
--- branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.cpp	                        (rev 0)
+++ branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,166 @@
+#include "qgspostgresfeatureiterator.h"
+
+#include "qgspostgresprovider.h"
+
+#include "qgslogger.h"
+
+// used from provider:
+// - providerId
+// - connectionRO
+// - geometryColumn
+// - srid
+// - sqlWhereClause
+// - featuresCounted
+// - declareCursor()
+// - getFeature()
+// - quotedIdentifier()
+
+QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresProvider* p,
+                            QgsAttributeList fetchAttributes,
+                            QgsRectangle rect,
+                            bool fetchGeometry,
+                            bool useIntersect )
+: QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect),
+  P(p)
+  , mFeatureQueueSize( 200 )
+{
+  P->mConnectionROMutex.lock();
+
+  QString cursorName = QString( "qgisf%1" ).arg( P->providerId );
+
+  QString whereClause;
+
+  if ( !rect.isEmpty() )
+  {
+    if ( useIntersect )
+    {
+      // Contributed by #qgis irc "creeping"
+      // This version actually invokes PostGIS's use of spatial indexes
+      whereClause = QString( "%1 && setsrid('BOX3D(%2)'::box3d,%3) and intersects(%1,setsrid('BOX3D(%2)'::box3d,%3))" )
+                    .arg( P->quotedIdentifier( P->geometryColumn ) )
+                    .arg( rect.asWktCoordinates() )
+                    .arg( P->srid );
+    }
+    else
+    {
+      whereClause = QString( "%1 && setsrid('BOX3D(%2)'::box3d,%3)" )
+                    .arg( P->quotedIdentifier( P->geometryColumn ) )
+                    .arg( rect.asWktCoordinates() )
+                    .arg( P->srid );
+    }
+  }
+
+  if ( !P->sqlWhereClause.isEmpty() )
+  {
+    if ( !whereClause.isEmpty() )
+      whereClause += " and ";
+
+    whereClause += "(" + P->sqlWhereClause + ")";
+  }
+
+  if ( !P->declareCursor( cursorName, fetchAttributes, fetchGeometry, whereClause ) )
+  {
+    mClosed = true;
+    return;
+  }
+
+  mFetched = 0;
+}
+
+QgsPostgresFeatureIterator::~QgsPostgresFeatureIterator()
+{
+  close();
+}
+
+
+bool QgsPostgresFeatureIterator::nextFeature(QgsFeature& feature)
+{
+  feature.setValid( false );
+
+  if ( mClosed )
+    return false;
+
+  QString cursorName = QString( "qgisf%1" ).arg( P->providerId );
+
+  if ( mFeatureQueue.empty() )
+  {
+    QString fetch = QString( "fetch forward %1 from %2" ).arg( mFeatureQueueSize ).arg( cursorName );
+    if ( P->connectionRO->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously
+    {
+      QgsDebugMsg( "PQsendQuery failed" );
+    }
+
+    QgsPostgresProvider::Result queryResult;
+    while (( queryResult = P->connectionRO->PQgetResult() ) )
+    {
+      int rows = PQntuples( queryResult );
+      if ( rows == 0 )
+        continue;
+
+      for ( int row = 0; row < rows; row++ )
+      {
+        mFeatureQueue.push( QgsFeature() );
+        P->getFeature( queryResult, row, mFetchGeometry, mFeatureQueue.back(), mFetchAttributes );
+      } // for each row in queue
+    }
+  }
+
+  if ( mFeatureQueue.empty() )
+  {
+    QgsDebugMsg( QString( "finished after %1 features" ).arg( mFetched ) );
+
+    close();
+
+    if ( P->featuresCounted < mFetched )
+    {
+      QgsDebugMsg( QString( "feature count adjusted from %1 to %2" ).arg( P->featuresCounted ).arg( mFetched ) );
+      P->featuresCounted = mFetched;
+    }
+    return false;
+  }
+
+  // Now return the next feature from the queue
+  if ( mFetchGeometry )
+  {
+    QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership();
+    feature.setGeometry( featureGeom );
+  }
+  else
+  {
+    feature.setGeometryAndOwnership( 0, 0 );
+  }
+  feature.setFeatureId( mFeatureQueue.front().id() );
+  feature.setAttributeMap( mFeatureQueue.front().attributeMap() );
+
+  mFeatureQueue.pop();
+  mFetched++;
+
+  feature.setValid( true );
+  return true;
+}
+
+bool QgsPostgresFeatureIterator::rewind()
+{
+  if ( mClosed )
+    return false;
+
+  //move cursor to first record
+  P->connectionRO->PQexecNR( QString( "move 0 in qgisf%1" ).arg( P->providerId ) );
+
+  mFeatureQueue.empty();
+
+  return true;
+}
+
+bool QgsPostgresFeatureIterator::close()
+{
+  if ( mClosed )
+    return false;
+
+  P->connectionRO->closeCursor( QString( "qgisf%1" ).arg( P->providerId ) );
+
+  P->mConnectionROMutex.unlock();
+
+  mClosed = true;
+  return true;
+}

Added: branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.h
===================================================================
--- branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.h	                        (rev 0)
+++ branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.h	2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,48 @@
+#ifndef QGSPOSTGRESFEATUREITERATOR_H
+#define QGSPOSTGRESFEATUREITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+#include <queue>
+
+class QgsPostgresProvider;
+
+class QgsPostgresFeatureIterator : public QgsVectorDataProviderIterator
+{
+public:
+  QgsPostgresFeatureIterator( QgsPostgresProvider* p,
+                              QgsAttributeList fetchAttributes,
+                              QgsRectangle rect,
+                              bool fetchGeometry,
+                              bool useIntersect );
+
+  ~QgsPostgresFeatureIterator();
+
+  //! fetch next feature, return true on success
+  virtual bool nextFeature(QgsFeature& f);
+
+  //! reset the iterator to the starting position
+  virtual bool rewind();
+
+  //! end of iterating: free the resources / lock
+  virtual bool close();
+
+protected:
+  QgsPostgresProvider* P;
+
+  int mFetched; // number of retrieved features
+
+  /**
+   * Feature queue that GetNextFeature will retrieve from
+   * before the next fetch from PostgreSQL
+   */
+  std::queue<QgsFeature> mFeatureQueue;
+
+  /**
+   * Maximal size of the feature queue
+   */
+  int mFeatureQueueSize;
+
+};
+
+#endif // QGSPOSTGRESFEATUREITERATOR_H

Modified: branches/threading-branch/src/providers/postgres/qgspostgresprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/postgres/qgspostgresprovider.cpp	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/postgres/qgspostgresprovider.cpp	2010-07-03 16:50:45 UTC (rev 13881)
@@ -37,6 +37,7 @@
 #include "qgsproviderextentcalcevent.h"
 
 #include "qgspostgresprovider.h"
+#include "qgspostgresfeatureiterator.h"
 
 #include "qgslogger.h"
 
@@ -56,10 +57,8 @@
 
 QgsPostgresProvider::QgsPostgresProvider( QString const & uri )
     : QgsVectorDataProvider( uri )
-    , mFetching( false )
     , mIsDbPrimaryKey( false )
     , geomType( QGis::WKBUnknown )
-    , mFeatureQueueSize( 200 )
     , mUseEstimatedMetadata( false )
     , mPrimaryKeyDefault( QString::null )
 {
@@ -304,11 +303,7 @@
 
 void QgsPostgresProvider::disconnectDb()
 {
-  if ( mFetching )
-  {
-    connectionRO->closeCursor( QString( "qgisf%1" ).arg( providerId ) );
-    mFetching = false;
-  }
+  mOldApiIter.close();
 
   if ( connectionRO )
   {
@@ -337,8 +332,8 @@
   for ( i = connections.begin(); i != connections.end() && i.value() != conn; i++ )
     ;
 
-  assert( i.value() == conn );
-  assert( i.value()->ref > 0 );
+  Q_ASSERT( i.value() == conn );
+  Q_ASSERT( i.value()->ref > 0 );
 
   if ( --i.value()->ref == 0 )
   {
@@ -520,131 +515,37 @@
   }
 }
 
-void QgsPostgresProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
+QgsFeatureIterator QgsPostgresProvider::getFeatures( QgsAttributeList fetchAttributes,
+                                                     QgsRectangle rect,
+                                                     bool fetchGeometry,
+                                                     bool useIntersect )
 {
-  QString cursorName = QString( "qgisf%1" ).arg( providerId );
+  return QgsFeatureIterator( new QgsPostgresFeatureIterator(this, fetchAttributes, rect, fetchGeometry, useIntersect ) );
+}
 
-  if ( mFetching )
-  {
-    connectionRO->closeCursor( cursorName );
-    mFetching = false;
 
-    while ( !mFeatureQueue.empty() )
-    {
-      mFeatureQueue.pop();
-    }
-  }
-
-  QString whereClause;
-
-  if ( !rect.isEmpty() )
-  {
-    if ( useIntersect )
-    {
-      // Contributed by #qgis irc "creeping"
-      // This version actually invokes PostGIS's use of spatial indexes
-      whereClause = QString( "%1 && setsrid('BOX3D(%2)'::box3d,%3) and intersects(%1,setsrid('BOX3D(%2)'::box3d,%3))" )
-                    .arg( quotedIdentifier( geometryColumn ) )
-                    .arg( rect.asWktCoordinates() )
-                    .arg( srid );
-    }
-    else
-    {
-      whereClause = QString( "%1 && setsrid('BOX3D(%2)'::box3d,%3)" )
-                    .arg( quotedIdentifier( geometryColumn ) )
-                    .arg( rect.asWktCoordinates() )
-                    .arg( srid );
-    }
-  }
-
-  if ( !sqlWhereClause.isEmpty() )
-  {
-    if ( !whereClause.isEmpty() )
-      whereClause += " and ";
-
-    whereClause += "(" + sqlWhereClause + ")";
-  }
-
-  mFetchGeom = fetchGeometry;
-  mAttributesToFetch = fetchAttributes;
-  if ( !declareCursor( cursorName, fetchAttributes, fetchGeometry, whereClause ) )
-    return;
-
-  mFetching = true;
-  mFetched = 0;
+void QgsPostgresProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
+{
+  if (!mOldApiIter.isClosed())
+    mOldApiIter.close();
+  mOldApiIter = getFeatures(fetchAttributes, rect, fetchGeometry, useIntersect);
 }
 
 bool QgsPostgresProvider::nextFeature( QgsFeature& feature )
 {
-  feature.setValid( false );
   if ( !valid )
   {
     QgsDebugMsg( "Read attempt on an invalid postgresql data source" );
     return false;
   }
 
-  if ( !mFetching )
+  if ( mOldApiIter.isClosed() )
   {
     QgsDebugMsg( "nextFeature() without select()" );
     return false;
   }
 
-  QString cursorName = QString( "qgisf%1" ).arg( providerId );
-
-  if ( mFeatureQueue.empty() )
-  {
-    QString fetch = QString( "fetch forward %1 from %2" ).arg( mFeatureQueueSize ).arg( cursorName );
-    if ( connectionRO->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously
-    {
-      QgsDebugMsg( "PQsendQuery failed" );
-    }
-
-    Result queryResult;
-    while (( queryResult = connectionRO->PQgetResult() ) )
-    {
-      int rows = PQntuples( queryResult );
-      if ( rows == 0 )
-        continue;
-
-      for ( int row = 0; row < rows; row++ )
-      {
-        mFeatureQueue.push( QgsFeature() );
-        getFeature( queryResult, row, mFetchGeom, mFeatureQueue.back(), mAttributesToFetch );
-      } // for each row in queue
-    }
-  }
-
-  if ( mFeatureQueue.empty() )
-  {
-    QgsDebugMsg( QString( "finished after %1 features" ).arg( mFetched ) );
-    connectionRO->closeCursor( cursorName );
-    mFetching = false;
-    if ( featuresCounted < mFetched )
-    {
-      QgsDebugMsg( QString( "feature count adjusted from %1 to %2" ).arg( featuresCounted ).arg( mFetched ) );
-      featuresCounted = mFetched;
-    }
-    return false;
-  }
-
-  // Now return the next feature from the queue
-  if ( mFetchGeom )
-  {
-    QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership();
-    feature.setGeometry( featureGeom );
-  }
-  else
-  {
-    feature.setGeometryAndOwnership( 0, 0 );
-  }
-  feature.setFeatureId( mFeatureQueue.front().id() );
-  feature.setAttributeMap( mFeatureQueue.front().attributeMap() );
-
-  mFeatureQueue.pop();
-  mFetched++;
-
-  feature.setValid( true );
-  return true;
+  return mOldApiIter.nextFeature( feature );
 }
 
 QString QgsPostgresProvider::whereClause( int featureId ) const
@@ -673,6 +574,8 @@
 
 bool QgsPostgresProvider::featureAtId( int featureId, QgsFeature& feature, bool fetchGeometry, QgsAttributeList fetchAttributes )
 {
+  QMutexLocker connectionROLocker(&mConnectionROMutex);
+
   feature.setValid( false );
   QString cursorName = QString( "qgisfid%1" ).arg( providerId );
 
@@ -758,13 +661,7 @@
 
 void QgsPostgresProvider::rewind()
 {
-  if ( mFetching )
-  {
-    //move cursor to first record
-    connectionRO->PQexecNR( QString( "move 0 in qgisf%1" ).arg( providerId ) );
-  }
-  mFeatureQueue.empty();
-  loadFields();
+  mOldApiIter.rewind();
 }
 
 /** @todo XXX Perhaps this should be promoted to QgsDataProvider? */
@@ -1586,6 +1483,8 @@
 
 bool QgsPostgresProvider::uniqueData( QString query, QString colName )
 {
+  QMutexLocker connectionROLocker(&mConnectionROMutex);
+
   // Check to see if the given column contains unique data
 
   bool isUnique = false;
@@ -1855,6 +1754,8 @@
 // Returns the minimum value of an attribute
 QVariant QgsPostgresProvider::minimumValue( int index )
 {
+  QMutexLocker connectionROLocker(&mConnectionROMutex);
+
   try
   {
     // get the field name
@@ -1880,6 +1781,8 @@
 // Returns the list of unique values of an attribute
 void QgsPostgresProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit )
 {
+  QMutexLocker connectionROLocker(&mConnectionROMutex);
+
   uniqueValues.clear();
 
   try
@@ -1917,6 +1820,8 @@
 
 void QgsPostgresProvider::enumValues( int index, QStringList& enumList )
 {
+  QMutexLocker connectionROLocker(&mConnectionROMutex);
+
   enumList.clear();
 
   QString typeName;
@@ -2048,6 +1953,8 @@
 // Returns the maximum value of an attribute
 QVariant QgsPostgresProvider::maximumValue( int index )
 {
+  QMutexLocker connectionROLocker(&mConnectionROMutex);
+
   try
   {
     // get the field name
@@ -2108,6 +2015,8 @@
 
 QVariant QgsPostgresProvider::defaultValue( int fieldId )
 {
+  QMutexLocker connectionROLocker(&mConnectionROMutex);
+
   try
   {
     return defaultValue( field( fieldId ).name() );
@@ -2748,6 +2657,8 @@
   if ( featuresCounted >= 0 )
     return featuresCounted;
 
+  QMutexLocker connectionROLocker(&mConnectionROMutex);
+
   // get total number of features
   QString sql;
 
@@ -2781,6 +2692,8 @@
 {
   if ( layerExtent.isEmpty() )
   {
+    QMutexLocker connectionROLocker(&mConnectionROMutex);
+
     QString sql;
     Result result;
     QString ext;

Modified: branches/threading-branch/src/providers/postgres/qgspostgresprovider.h
===================================================================
--- branches/threading-branch/src/providers/postgres/qgspostgresprovider.h	2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/postgres/qgspostgresprovider.h	2010-07-03 16:50:45 UTC (rev 13881)
@@ -26,9 +26,10 @@
 #include "qgsvectordataprovider.h"
 #include "qgsrectangle.h"
 #include <list>
-#include <queue>
 #include <fstream>
 #include <set>
+#include <vector>
+#include <QMutex>
 
 class QgsFeature;
 class QgsField;
@@ -91,6 +92,11 @@
      */
     virtual bool nextFeature( QgsFeature& feature );
 
+    virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                            QgsRectangle rect = QgsRectangle(),
+                                            bool fetchGeometry = true,
+                                            bool useIntersect = false );
+
     /**
       * Gets the feature at the given feature ID.
       * @param featureId id of the feature
@@ -363,12 +369,13 @@
     */
     bool parseDomainCheckConstraint( QStringList& enumValues, const QString& attributeName ) const;
 
-    bool mFetching; // true if a cursor was declared
-    int mFetched; // number of retrieved features
     std::vector < QgsFeature > features;
     QgsFieldMap attributeFields;
     QString mDataComment;
 
+    QgsFeatureIterator mOldApiIter;
+    friend class QgsPostgresFeatureIterator;
+
     //! Data source URI struct for this layer
     QgsDataSourceURI mUri;
 
@@ -440,17 +447,6 @@
     mutable long featuresCounted;
 
     /**
-     * Feature queue that GetNextFeature will retrieve from
-     * before the next fetch from PostgreSQL
-     */
-    std::queue<QgsFeature> mFeatureQueue;
-
-    /**
-     * Maximal size of the feature queue
-     */
-    int mFeatureQueueSize;
-
-    /**
      * Flag indicating whether data from binary cursors must undergo an
      * endian conversion prior to use
      @note
@@ -706,6 +702,8 @@
      * Default value for primary key
      */
     QString mPrimaryKeyDefault;
-};
 
+    mutable QMutex mConnectionROMutex;
+  };
+
 #endif



More information about the QGIS-commit mailing list