[QGIS Commit] r13897 - in branches/threading-branch/src/providers: delimitedtext gpx memory spatialite

svn_qgis at osgeo.org svn_qgis at osgeo.org
Wed Jul 7 14:37:02 EDT 2010


Author: wonder
Date: 2010-07-07 18:37:02 +0000 (Wed, 07 Jul 2010)
New Revision: 13897

Added:
   branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp
   branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.h
   branches/threading-branch/src/providers/gpx/qgsgpxfeatureiterator.cpp
   branches/threading-branch/src/providers/gpx/qgsgpxfeatureiterator.h
   branches/threading-branch/src/providers/memory/qgsmemoryfeatureiterator.cpp
   branches/threading-branch/src/providers/memory/qgsmemoryfeatureiterator.h
   branches/threading-branch/src/providers/spatialite/qgsspatialitefeatureiterator.cpp
   branches/threading-branch/src/providers/spatialite/qgsspatialitefeatureiterator.h
Modified:
   branches/threading-branch/src/providers/delimitedtext/CMakeLists.txt
   branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp
   branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextprovider.h
   branches/threading-branch/src/providers/gpx/CMakeLists.txt
   branches/threading-branch/src/providers/gpx/qgsgpxprovider.cpp
   branches/threading-branch/src/providers/gpx/qgsgpxprovider.h
   branches/threading-branch/src/providers/memory/CMakeLists.txt
   branches/threading-branch/src/providers/memory/qgsmemoryprovider.cpp
   branches/threading-branch/src/providers/memory/qgsmemoryprovider.h
   branches/threading-branch/src/providers/spatialite/CMakeLists.txt
   branches/threading-branch/src/providers/spatialite/qgsspatialiteprovider.cpp
   branches/threading-branch/src/providers/spatialite/qgsspatialiteprovider.h
Log:
Modified more providers to use new API: delimited text, gpx, memory, spatialite.
All of them now use locking.


Modified: branches/threading-branch/src/providers/delimitedtext/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/providers/delimitedtext/CMakeLists.txt	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/delimitedtext/CMakeLists.txt	2010-07-07 18:37:02 UTC (rev 13897)
@@ -2,7 +2,7 @@
 ########################################################
 # Files
 
-SET (DTEXT_SRCS qgsdelimitedtextprovider.cpp)
+SET (DTEXT_SRCS qgsdelimitedtextprovider.cpp qgsdelimitedtextfeatureiterator.cpp)
 
 SET (DTEXT_MOC_HDRS	qgsdelimitedtextprovider.h)
 

Added: branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp
===================================================================
--- branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp	                        (rev 0)
+++ branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp	2010-07-07 18:37:02 UTC (rev 13897)
@@ -0,0 +1,191 @@
+#include "qgsdelimitedtextfeatureiterator.h"
+
+#include "qgsdelimitedtextprovider.h"
+
+#include "qgsapplication.h"
+#include "qgslogger.h"
+
+#include <QTextStream>
+
+// used from provider:
+// - mStream
+// - attributeFields
+// - mXFieldIndex, mYFieldIndex
+// - mInvalidLines, mShowInvalidLines
+// - splitLine()
+
+QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTextProvider* p,
+                                                                  QgsAttributeList fetchAttributes,
+                                                                  QgsRectangle rect,
+                                                                  bool fetchGeometry,
+                                                                  bool useIntersect )
+: QgsVectorDataProviderIterator( fetchAttributes, rect, fetchGeometry, useIntersect ),
+  P(p)
+{
+  P->mStreamMutex.lock();
+  rewind();
+}
+
+QgsDelimitedTextFeatureIterator::~QgsDelimitedTextFeatureIterator()
+{
+  close();
+}
+
+bool QgsDelimitedTextFeatureIterator::boundsCheck( double x, double y )
+{
+  // no selection rectangle => always in the bounds
+  if ( mRect.isEmpty() )
+    return true;
+
+  return ( x <= mRect.xMaximum() ) && ( x >= mRect.xMinimum() ) &&
+         ( y <= mRect.yMaximum() ) && ( y >= mRect.yMinimum() );
+}
+
+
+bool QgsDelimitedTextFeatureIterator::nextFeature(QgsFeature& feature)
+{
+  if (mClosed)
+    return false;
+
+  // before we do anything else, assume that there's something wrong with
+  // the feature
+  feature.setValid( false );
+  while ( ! P->mStream->atEnd() )
+  {
+    double x = 0.0;
+    double y = 0.0;
+    QString line = P->mStream->readLine(); // Default local 8 bit encoding
+
+    // lex the tokens from the current data line
+    QStringList tokens = P->splitLine( line );
+
+    bool xOk = false;
+    bool yOk = false;
+
+    // Skip indexing malformed lines.
+    if ( P->attributeFields.size() == tokens.size() )
+    {
+      x = tokens[P->mXFieldIndex].toDouble( &xOk );
+      y = tokens[P->mYFieldIndex].toDouble( &yOk );
+    }
+
+    if ( !( xOk && yOk ) )
+    {
+      // Accumulate any lines that weren't ok, to report on them
+      // later, and look at the next line in the file, but only if
+      // we need to.
+      QgsDebugMsg( "Malformed line : " + line );
+      if ( P->mShowInvalidLines )
+        P->mInvalidLines << line;
+
+      continue;
+    }
+
+    // Give every valid line in the file an id, even if it's not
+    // in the current extent or bounds.
+    ++mFid;             // increment to next feature ID
+
+    // skip the feature if it's out of current bounds
+    if ( ! boundsCheck( x, y ) )
+      continue;
+
+    // at this point, one way or another, the current feature values
+    // are valid
+    feature.setValid( true );
+
+    feature.setFeatureId( mFid );
+
+    QByteArray  buffer;
+    QDataStream s( &buffer, static_cast<QIODevice::OpenMode>( QIODevice::WriteOnly ) ); // open on buffers's data
+
+    switch ( QgsApplication::endian() )
+    {
+      case QgsApplication::NDR :
+        // we're on a little-endian platform, so tell the data
+        // stream to use that
+        s.setByteOrder( QDataStream::LittleEndian );
+        s << ( quint8 )1; // 1 is for little-endian
+        break;
+      case QgsApplication::XDR :
+        // don't change byte order since QDataStream is big endian by default
+        s << ( quint8 )0; // 0 is for big-endian
+        break;
+      default :
+        QgsDebugMsg( "unknown endian" );
+        //delete [] geometry;
+        return false;
+    }
+
+    s << ( quint32 )QGis::WKBPoint;
+    s << x;
+    s << y;
+
+    unsigned char* geometry = new unsigned char[buffer.size()];
+    memcpy( geometry, buffer.data(), buffer.size() );
+
+    feature.setGeometryAndOwnership( geometry, buffer.size() );
+
+    for ( QgsAttributeList::const_iterator i = mFetchAttributes.begin();
+          i != mFetchAttributes.end();
+          ++i )
+    {
+      QVariant val;
+      switch ( P->attributeFields[*i].type() )
+      {
+        case QVariant::Int:
+          if( !tokens[*i].isEmpty() )
+            val = QVariant( tokens[*i].toInt() );
+          else
+            val = QVariant( P->attributeFields[*i].type() );
+          break;
+        case QVariant::Double:
+          if( !tokens[*i].isEmpty() )
+            val = QVariant( tokens[*i].toDouble() );
+          else
+            val = QVariant( P->attributeFields[*i].type() );
+          break;
+        default:
+          val = QVariant( tokens[*i] );
+          break;
+      }
+      feature.addAttribute( *i, val );
+    }
+
+    // We have a good line, so return
+    return true;
+
+  } // ! textStream EOF
+
+  // End of the file. If there are any lines that couldn't be
+  // loaded, display them now.
+
+  P->showInvalidLinesErrors();
+
+  return false;
+}
+
+bool QgsDelimitedTextFeatureIterator::rewind()
+{
+  if (mClosed)
+    return false;
+
+  // Reset feature id to 0
+  mFid = 0;
+
+  // Skip ahead one line since first record is always assumed to be
+  // the header record
+  P->mStream->seek( 0 );
+  P->mStream->readLine();
+
+  return true;
+}
+
+bool QgsDelimitedTextFeatureIterator::close()
+{
+  if (mClosed)
+    return false;
+
+  P->mStreamMutex.unlock();
+  mClosed = true;
+  return true;
+}

Added: branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.h
===================================================================
--- branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.h	                        (rev 0)
+++ branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.h	2010-07-07 18:37:02 UTC (rev 13897)
@@ -0,0 +1,48 @@
+#ifndef QGSDELIMITEDTEXTFEATUREITERATOR_H
+#define QGSDELIMITEDTEXTFEATUREITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+class QgsDelimitedTextProvider;
+
+class QgsDelimitedTextFeatureIterator : public QgsVectorDataProviderIterator
+{
+public:
+  QgsDelimitedTextFeatureIterator( QgsDelimitedTextProvider* p,
+                                   QgsAttributeList fetchAttributes,
+                                   QgsRectangle rect,
+                                   bool fetchGeometry,
+                                   bool useIntersect );
+
+  ~QgsDelimitedTextFeatureIterator();
+
+  //! 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();
+
+
+  /**
+   * Check to see if the point is withn the selection
+   * rectangle
+   * @param x X value of point
+   * @param y Y value of point
+   * @return True if point is within the rectangle
+  */
+  bool boundsCheck( double x, double y );
+
+
+protected:
+  QgsDelimitedTextProvider* P;
+
+  //! Current feature id
+  long mFid;
+
+};
+
+
+#endif // QGSDELIMITEDTEXTFEATUREITERATOR_H

Modified: branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp	2010-07-07 18:37:02 UTC (rev 13897)
@@ -17,8 +17,8 @@
 /* $Id$ */
 
 #include "qgsdelimitedtextprovider.h"
+#include "qgsdelimitedtextfeatureiterator.h"
 
-
 #include <QtGlobal>
 #include <QFile>
 #include <QDataStream>
@@ -30,7 +30,6 @@
 #include <QUrl>
 
 
-#include "qgsapplication.h"
 #include "qgsdataprovider.h"
 #include "qgsfeature.h"
 #include "qgsfield.h"
@@ -46,7 +45,7 @@
 
 QStringList QgsDelimitedTextProvider::splitLine( QString line )
 {
-  QgsDebugMsg( "Attempting to split the input line: " + line + " using delimiter " + mDelimiter );
+  //QgsDebugMsg( "Attempting to split the input line: " + line + " using delimiter " + mDelimiter );
 
   QStringList parts;
   if ( mDelimiterType == "regexp" )
@@ -54,7 +53,7 @@
   else
     parts = line.split( mDelimiter );
 
-  QgsDebugMsg( "Split line into " + QString::number( parts.size() ) + " parts" );
+  //QgsDebugMsg( "Split line into " + QString::number( parts.size() ) + " parts" );
 
   if ( mDelimiterType == "plain" )
   {
@@ -146,8 +145,6 @@
   else
     mDelimiter.replace( "\\t", "\t" ); // replace "\t" with a real tabulator
 
-  // Set the selection rectangle to null
-  mSelectionRectangle = QgsRectangle();
   // assume the layer is invalid until proven otherwise
   mValid = false;
   if ( mFileName.isEmpty() || mDelimiter.isEmpty() || xField.isEmpty() || yField.isEmpty() )
@@ -329,121 +326,47 @@
   return "Delimited text file";
 }
 
+QgsFeatureIterator QgsDelimitedTextProvider::getFeatures( QgsAttributeList fetchAttributes,
+                                                          QgsRectangle rect,
+                                                          bool fetchGeometry,
+                                                          bool useIntersect )
+{
+  return QgsFeatureIterator( new QgsDelimitedTextFeatureIterator(this, fetchAttributes, rect, fetchGeometry, useIntersect));
+}
 
+
 bool QgsDelimitedTextProvider::nextFeature( QgsFeature& feature )
 {
-  // before we do anything else, assume that there's something wrong with
-  // the feature
-  feature.setValid( false );
-  while ( ! mStream->atEnd() )
+  if (mOldApiIter.nextFeature(feature))
+    return true;
+  else
   {
-    double x = 0.0;
-    double y = 0.0;
-    QString line = mStream->readLine(); // Default local 8 bit encoding
+    mOldApiIter.close(); // make sure to unlock the layer
+    return false;
+  }
+}
 
-    // lex the tokens from the current data line
-    QStringList tokens = splitLine( line );
 
-    bool xOk = false;
-    bool yOk = false;
+void QgsDelimitedTextProvider::select( QgsAttributeList fetchAttributes,
+                                       QgsRectangle rect,
+                                       bool fetchGeometry,
+                                       bool useIntersect )
+{
+  mOldApiIter.close();
+  mOldApiIter = getFeatures(fetchAttributes, rect, fetchGeometry, useIntersect);
+}
 
-    // Skip indexing malformed lines.
-    if ( attributeFields.size() == tokens.size() )
-    {
-      x = tokens[mXFieldIndex].toDouble( &xOk );
-      y = tokens[mYFieldIndex].toDouble( &yOk );
-    }
+void QgsDelimitedTextProvider::rewind()
+{
+  mOldApiIter.rewind();
+}
 
-    if ( !( xOk && yOk ) )
-    {
-      // Accumulate any lines that weren't ok, to report on them
-      // later, and look at the next line in the file, but only if
-      // we need to.
-      QgsDebugMsg( "Malformed line : " + line );
-      if ( mShowInvalidLines )
-        mInvalidLines << line;
 
-      continue;
-    }
 
-    // Give every valid line in the file an id, even if it's not
-    // in the current extent or bounds.
-    ++mFid;             // increment to next feature ID
+void QgsDelimitedTextProvider::showInvalidLinesErrors()
+{
+  // TODO: this should be modified to only set an error string that can be read from provider
 
-    // skip the feature if it's out of current bounds
-    if ( ! boundsCheck( x, y ) )
-      continue;
-
-    // at this point, one way or another, the current feature values
-    // are valid
-    feature.setValid( true );
-
-    feature.setFeatureId( mFid );
-
-    QByteArray  buffer;
-    QDataStream s( &buffer, static_cast<QIODevice::OpenMode>( QIODevice::WriteOnly ) ); // open on buffers's data
-
-    switch ( QgsApplication::endian() )
-    {
-      case QgsApplication::NDR :
-        // we're on a little-endian platform, so tell the data
-        // stream to use that
-        s.setByteOrder( QDataStream::LittleEndian );
-        s << ( quint8 )1; // 1 is for little-endian
-        break;
-      case QgsApplication::XDR :
-        // don't change byte order since QDataStream is big endian by default
-        s << ( quint8 )0; // 0 is for big-endian
-        break;
-      default :
-        QgsDebugMsg( "unknown endian" );
-        //delete [] geometry;
-        return false;
-    }
-
-    s << ( quint32 )QGis::WKBPoint;
-    s << x;
-    s << y;
-
-    unsigned char* geometry = new unsigned char[buffer.size()];
-    memcpy( geometry, buffer.data(), buffer.size() );
-
-    feature.setGeometryAndOwnership( geometry, sizeof( wkbPoint ) );
-
-    for ( QgsAttributeList::const_iterator i = mAttributesToFetch.begin();
-          i != mAttributesToFetch.end();
-          ++i )
-    {
-      QVariant val;
-      switch ( attributeFields[*i].type() )
-      {
-        case QVariant::Int:
-          if( !tokens[*i].isEmpty() )
-            val = QVariant( tokens[*i].toInt() );
-          else
-            val = QVariant( attributeFields[*i].type() );
-          break;
-        case QVariant::Double:
-          if( !tokens[*i].isEmpty() )
-            val = QVariant( tokens[*i].toDouble() );
-          else
-            val = QVariant( attributeFields[*i].type() );
-          break;
-        default:
-          val = QVariant( tokens[*i] );
-          break;
-      }
-      feature.addAttribute( *i, val );
-    }
-
-    // We have a good line, so return
-    return true;
-
-  } // ! textStream EOF
-
-  // End of the file. If there are any lines that couldn't be
-  // loaded, display them now.
-
   if ( mShowInvalidLines && !mInvalidLines.isEmpty() )
   {
     mShowInvalidLines = false;
@@ -463,34 +386,10 @@
     // We no longer need these lines.
     mInvalidLines.empty();
   }
-
-  return false;
-
-} // nextFeature
-
-
-void QgsDelimitedTextProvider::select( QgsAttributeList fetchAttributes,
-                                       QgsRectangle rect,
-                                       bool fetchGeometry,
-                                       bool useIntersect )
-{
-  mSelectionRectangle = rect;
-  mAttributesToFetch = fetchAttributes;
-  mFetchGeom = fetchGeometry;
-  if ( rect.isEmpty() )
-  {
-    mSelectionRectangle = mExtent;
-  }
-  else
-  {
-    mSelectionRectangle = rect;
-  }
-  rewind();
 }
 
 
 
-
 // Return the extent of the layer
 QgsRectangle QgsDelimitedTextProvider::extent()
 {
@@ -527,34 +426,12 @@
   return attributeFields;
 }
 
-void QgsDelimitedTextProvider::rewind()
-{
-  // Reset feature id to 0
-  mFid = 0;
-  // Skip ahead one line since first record is always assumed to be
-  // the header record
-  mStream->seek( 0 );
-  mStream->readLine();
-}
-
 bool QgsDelimitedTextProvider::isValid()
 {
   return mValid;
 }
 
-/**
- * Check to see if the point is within the selection rectangle
- */
-bool QgsDelimitedTextProvider::boundsCheck( double x, double y )
-{
-  // no selection rectangle => always in the bounds
-  if ( mSelectionRectangle.isEmpty() )
-    return true;
 
-  return ( x <= mSelectionRectangle.xMaximum() ) && ( x >= mSelectionRectangle.xMinimum() ) &&
-         ( y <= mSelectionRectangle.yMaximum() ) && ( y >= mSelectionRectangle.yMinimum() );
-}
-
 int QgsDelimitedTextProvider::capabilities() const
 {
   return NoCapabilities;

Modified: branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextprovider.h
===================================================================
--- branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextprovider.h	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/delimitedtext/qgsdelimitedtextprovider.h	2010-07-07 18:37:02 UTC (rev 13897)
@@ -20,6 +20,7 @@
 #include "qgsvectordataprovider.h"
 
 #include <QStringList>
+#include <QMutex>
 
 class QgsFeature;
 class QgsField;
@@ -79,6 +80,11 @@
      */
     virtual bool nextFeature( QgsFeature& feature );
 
+    virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                            QgsRectangle rect = QgsRectangle(),
+                                            bool fetchGeometry = true,
+                                            bool useIntersect = false );
+
     /**
      * Get feature type.
      * @return int representing the feature type
@@ -156,19 +162,7 @@
 
     /* new functions */
 
-    /**
-     * Check to see if the point is withn the selection
-     * rectangle
-     * @param x X value of point
-     * @param y Y value of point
-     * @return True if point is within the rectangle
-    */
-    bool boundsCheck( double x, double y );
 
-
-
-
-
   private:
 
     //! Fields
@@ -187,10 +181,6 @@
     //! Layer extent
     QgsRectangle mExtent;
 
-    //! Current selection rectangle
-
-    QgsRectangle mSelectionRectangle;
-
     //! Text file
     QFile *mFile;
 
@@ -198,8 +188,6 @@
 
     bool mValid;
 
-    int mGeomType;
-
     long mNumberFeatures;
 
     //! Storage for any lines in the file that couldn't be loaded
@@ -207,18 +195,12 @@
     //! Only want to show the invalid lines once to the user
     bool mShowInvalidLines;
 
-    //! Feature id
-    long mFid;
+    QStringList splitLine( QString line );
 
-    struct wkbPoint
-    {
-      unsigned char byteOrder;
-      quint32 wkbType;
-      double x;
-      double y;
-    };
-    wkbPoint mWKBpt;
+    void showInvalidLinesErrors();
 
-    QStringList splitLine( QString line );
+    friend class QgsDelimitedTextFeatureIterator;
+    QgsFeatureIterator mOldApiIter;
 
+    QMutex mStreamMutex;
 };

Modified: branches/threading-branch/src/providers/gpx/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/providers/gpx/CMakeLists.txt	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/gpx/CMakeLists.txt	2010-07-07 18:37:02 UTC (rev 13897)
@@ -2,7 +2,7 @@
 ########################################################
 # Files
 
-SET (GPX_SRCS qgsgpxprovider.cpp gpsdata.cpp)
+SET (GPX_SRCS qgsgpxprovider.cpp gpsdata.cpp qgsgpxfeatureiterator.cpp)
 
 SET (GPX_MOC_HDRS
 	qgsgpxprovider.h

Added: branches/threading-branch/src/providers/gpx/qgsgpxfeatureiterator.cpp
===================================================================
--- branches/threading-branch/src/providers/gpx/qgsgpxfeatureiterator.cpp	                        (rev 0)
+++ branches/threading-branch/src/providers/gpx/qgsgpxfeatureiterator.cpp	2010-07-07 18:37:02 UTC (rev 13897)
@@ -0,0 +1,368 @@
+#include "qgsgpxfeatureiterator.h"
+#include "qgsgpxprovider.h"
+#include "gpsdata.h"
+
+#include "qgsapplication.h"
+#include "qgsgeometry.h"
+#include "qgslogger.h"
+
+#include <cstring>
+
+
+// used from provider:
+// - mFeatureType
+// - data
+
+QgsGPXFeatureIterator::QgsGPXFeatureIterator( QgsGPXProvider* p,
+                                              QgsAttributeList fetchAttributes,
+                                              QgsRectangle rect,
+                                              bool fetchGeometry,
+                                              bool useIntersect )
+ : QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect ),
+   P(p)
+{
+  P->mDataMutex.lock();
+
+  if ( rect.isEmpty() )
+  {
+    mRect = P->extent();
+  }
+  else
+  {
+    mRect = rect;
+  }
+
+  rewind();
+}
+
+QgsGPXFeatureIterator::~QgsGPXFeatureIterator()
+{
+  close();
+}
+
+bool QgsGPXFeatureIterator::nextFeature(QgsFeature& feature)
+{
+  if (mClosed)
+    return false;
+
+  feature.setValid( false );
+
+  if ( P->mFeatureType == QgsGPXProvider::WaypointType )
+  {
+    return nextWaypoint(feature);
+  }
+  else if ( P->mFeatureType == QgsGPXProvider::RouteType )
+  {
+    return nextRoute(feature);
+  }
+  else if ( P->mFeatureType == QgsGPXProvider::TrackType )
+  {
+    return nextTrack(feature);
+  }
+
+  return false;
+}
+
+bool QgsGPXFeatureIterator::nextWaypoint(QgsFeature& feature)
+{
+  // go through the list of waypoints and return the first one that is in
+  // the bounds rectangle
+  for ( ; mWptIter != P->data->waypointsEnd(); ++mWptIter )
+  {
+    const QgsWaypoint* wpt;
+    wpt = &( *mWptIter );
+    if ( ! boundsCheck( wpt->lon, wpt->lat ) )
+      continue;
+
+    feature.setFeatureId( wpt->id );
+    feature.setValid( true );
+
+    // some wkb voodoo
+    if ( mFetchGeometry )
+    {
+      char* geo = new char[21];
+      std::memset( geo, 0, 21 );
+      geo[0] = QgsApplication::endian();
+      geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBPoint;
+      std::memcpy( geo + 5, &wpt->lon, sizeof( double ) );
+      std::memcpy( geo + 13, &wpt->lat, sizeof( double ) );
+      feature.setGeometryAndOwnership(( unsigned char * )geo, 1+4+8+8 );
+    }
+
+    // add attributes if they are wanted
+    for ( QgsAttributeList::const_iterator iter = mFetchAttributes.begin(); iter != mFetchAttributes.end(); ++iter )
+    {
+      switch ( *iter )
+      {
+        case QgsGPXProvider::NameAttr:
+          feature.addAttribute( QgsGPXProvider::NameAttr, QVariant( wpt->name ) );
+          break;
+        case QgsGPXProvider::EleAttr:
+          if ( wpt->ele != -std::numeric_limits<double>::max() )
+            feature.addAttribute( QgsGPXProvider::EleAttr, QVariant( wpt->ele ) );
+          break;
+        case QgsGPXProvider::SymAttr:
+          feature.addAttribute( QgsGPXProvider::SymAttr, QVariant( wpt->sym ) );
+          break;
+        case QgsGPXProvider::CmtAttr:
+          feature.addAttribute( QgsGPXProvider::CmtAttr, QVariant( wpt->cmt ) );
+          break;
+        case QgsGPXProvider::DscAttr:
+          feature.addAttribute( QgsGPXProvider::DscAttr, QVariant( wpt->desc ) );
+          break;
+        case QgsGPXProvider::SrcAttr:
+          feature.addAttribute( QgsGPXProvider::SrcAttr, QVariant( wpt->src ) );
+          break;
+        case QgsGPXProvider::URLAttr:
+          feature.addAttribute( QgsGPXProvider::URLAttr, QVariant( wpt->url ) );
+          break;
+        case QgsGPXProvider::URLNameAttr:
+          feature.addAttribute( QgsGPXProvider::URLNameAttr, QVariant( wpt->urlname ) );
+          break;
+      }
+    }
+
+    ++mWptIter;
+    return true;
+  }
+
+  return false;
+}
+
+
+bool QgsGPXFeatureIterator::nextRoute(QgsFeature& feature)
+{
+  // go through the routes and return the first one that is in the bounds
+  // rectangle
+  for ( ; mRteIter != P->data->routesEnd(); ++mRteIter )
+  {
+    const QgsRoute* rte;
+    rte = &( *mRteIter );
+
+    if ( rte->points.size() == 0 )
+      continue;
+
+    if ( !boundsCheckRect( rte->xMin, rte->yMin, rte->xMax, rte->yMax ) )
+      continue;
+
+    // some wkb voodoo
+    int nPoints = rte->points.size();
+    char* geo = new char[9 + 16 * nPoints];
+    std::memset( geo, 0, 9 + 16 * nPoints );
+    geo[0] = QgsApplication::endian();
+    geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString;
+    std::memcpy( geo + 5, &nPoints, 4 );
+    for ( uint i = 0; i < rte->points.size(); ++i )
+    {
+      std::memcpy( geo + 9 + 16 * i, &rte->points[i].lon, sizeof( double ) );
+      std::memcpy( geo + 9 + 16 * i + 8, &rte->points[i].lat, sizeof( double ) );
+    }
+
+    //create QgsGeometry and use it for intersection test
+    //if geometry is to be fetched, it is attached to the feature, otherwise we delete it
+    QgsGeometry* theGeometry = new QgsGeometry();
+    theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * nPoints );
+    bool intersection = theGeometry->intersects( mRect );//use geos for precise intersection test
+
+    if ( !intersection )
+    {
+      delete theGeometry;
+      continue;
+    }
+
+    if ( mFetchGeometry )
+    {
+      feature.setGeometry( theGeometry );
+    }
+    else
+    {
+      delete theGeometry;
+    }
+    feature.setFeatureId( rte->id );
+    feature.setValid( true );
+
+    // add attributes if they are wanted
+    for ( QgsAttributeList::const_iterator iter = mFetchAttributes.begin(); iter != mFetchAttributes.end(); ++iter )
+    {
+      switch ( *iter )
+      {
+        case QgsGPXProvider::NameAttr:
+          feature.addAttribute( QgsGPXProvider::NameAttr, QVariant( rte->name ) );
+          break;
+        case QgsGPXProvider::NumAttr:
+          if ( rte->number != std::numeric_limits<int>::max() )
+            feature.addAttribute( QgsGPXProvider::NumAttr, QVariant( rte->number ) );
+          break;
+        case QgsGPXProvider::CmtAttr:
+          feature.addAttribute( QgsGPXProvider::CmtAttr, QVariant( rte->cmt ) );
+          break;
+        case QgsGPXProvider::DscAttr:
+          feature.addAttribute( QgsGPXProvider::DscAttr, QVariant( rte->desc ) );
+          break;
+        case QgsGPXProvider::SrcAttr:
+          feature.addAttribute( QgsGPXProvider::SrcAttr, QVariant( rte->src ) );
+          break;
+        case QgsGPXProvider::URLAttr:
+          feature.addAttribute( QgsGPXProvider::URLAttr, QVariant( rte->url ) );
+          break;
+        case QgsGPXProvider::URLNameAttr:
+          feature.addAttribute( QgsGPXProvider::URLNameAttr, QVariant( rte->urlname ) );
+          break;
+      }
+    }
+
+    ++mRteIter;
+    return true;
+  }
+  return false;
+}
+
+bool QgsGPXFeatureIterator::nextTrack(QgsFeature& feature)
+{
+  // go through the tracks and return the first one that is in the bounds
+  // rectangle
+  for ( ; mTrkIter != P->data->tracksEnd(); ++mTrkIter )
+  {
+    const QgsTrack* trk;
+    trk = &( *mTrkIter );
+
+    QgsDebugMsg( QString( "GPX feature track segments: %1" ).arg( trk->segments.size() ) );
+    if ( trk->segments.size() == 0 )
+      continue;
+
+    // A track consists of several segments. Add all those segments into one.
+    int totalPoints = 0;;
+    for ( std::vector<QgsTrackSegment>::size_type i = 0; i < trk->segments.size(); i ++ )
+    {
+      totalPoints += trk->segments[i].points.size();
+    }
+    if ( totalPoints == 0 )
+      continue;
+
+    QgsDebugMsg( "GPX feature track total points: " + QString::number( totalPoints ) );
+
+    if ( !boundsCheckRect( trk->xMin, trk->yMin, trk->xMax, trk->yMax ) )
+      continue;
+
+    // some wkb voodoo
+    char* geo = new char[9 + 16 * totalPoints];
+    if ( !geo )
+    {
+      QgsDebugMsg( "Too large track!!!" );
+      return false;
+    }
+    std::memset( geo, 0, 9 + 16 * totalPoints );
+    geo[0] = QgsApplication::endian();
+    geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString;
+    std::memcpy( geo + 5, &totalPoints, 4 );
+
+    int thisPoint = 0;
+    for ( std::vector<QgsTrackSegment>::size_type k = 0; k < trk->segments.size(); k++ )
+    {
+      int nPoints = trk->segments[k].points.size();
+      for ( int i = 0; i < nPoints; ++i )
+      {
+        std::memcpy( geo + 9 + 16 * thisPoint,     &trk->segments[k].points[i].lon, sizeof( double ) );
+        std::memcpy( geo + 9 + 16 * thisPoint + 8, &trk->segments[k].points[i].lat, sizeof( double ) );
+        thisPoint++;
+      }
+    }
+
+    //create QgsGeometry and use it for intersection test
+    //if geometry is to be fetched, it is attached to the feature, otherwise we delete it
+    QgsGeometry* theGeometry = new QgsGeometry();
+    theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * totalPoints );
+    bool intersection = theGeometry->intersects( mRect );//use geos for precise intersection test
+
+    if ( !intersection ) //no intersection, delete geometry and move on
+    {
+      delete theGeometry;
+      continue;
+    }
+
+    if ( mFetchGeometry )
+    {
+      feature.setGeometry( theGeometry );
+    }
+    else
+    {
+      delete theGeometry;
+    }
+    feature.setFeatureId( trk->id );
+    feature.setValid( true );
+
+    // add attributes if they are wanted
+    for ( QgsAttributeList::const_iterator iter = mFetchAttributes.begin(); iter != mFetchAttributes.end(); ++iter )
+    {
+      switch ( *iter )
+      {
+        case QgsGPXProvider::NameAttr:
+          feature.addAttribute( QgsGPXProvider::NameAttr, QVariant( trk->name ) );
+          break;
+        case QgsGPXProvider::NumAttr:
+          if ( trk->number != std::numeric_limits<int>::max() )
+            feature.addAttribute( QgsGPXProvider::NumAttr, QVariant( trk->number ) );
+          break;
+        case QgsGPXProvider::CmtAttr:
+          feature.addAttribute( QgsGPXProvider::CmtAttr, QVariant( trk->cmt ) );
+          break;
+        case QgsGPXProvider::DscAttr:
+          feature.addAttribute( QgsGPXProvider::DscAttr, QVariant( trk->desc ) );
+          break;
+        case QgsGPXProvider::SrcAttr:
+          feature.addAttribute( QgsGPXProvider::SrcAttr, QVariant( trk->src ) );
+          break;
+        case QgsGPXProvider::URLAttr:
+          feature.addAttribute( QgsGPXProvider::URLAttr, QVariant( trk->url ) );
+          break;
+        case QgsGPXProvider::URLNameAttr:
+          feature.addAttribute( QgsGPXProvider::URLNameAttr, QVariant( trk->urlname ) );
+          break;
+      }
+    }
+
+    ++mTrkIter;
+    return true;
+  }
+  return false;
+}
+
+
+bool QgsGPXFeatureIterator::boundsCheck( double x, double y )
+{
+  return ( x <= mRect.xMaximum() ) && ( x >= mRect.xMinimum() ) &&
+         ( y <= mRect.yMaximum() ) && ( y >= mRect.yMinimum() );
+}
+
+bool QgsGPXFeatureIterator::boundsCheckRect( double xmin, double ymin, double xmax, double ymax )
+{
+  return ( xmax >= mRect.xMinimum() ) && ( xmin <= mRect.xMaximum() ) &&
+         ( ymax >= mRect.yMinimum() ) && ( ymin <= mRect.yMaximum() );
+}
+
+
+
+bool QgsGPXFeatureIterator::rewind()
+{
+  if (mClosed)
+    return false;
+
+  if ( P->mFeatureType == QgsGPXProvider::WaypointType )
+    mWptIter = P->data->waypointsBegin();
+  else if ( P->mFeatureType == QgsGPXProvider::RouteType )
+    mRteIter = P->data->routesBegin();
+  else if ( P->mFeatureType == QgsGPXProvider::TrackType )
+    mTrkIter = P->data->tracksBegin();
+
+  return true;
+}
+
+bool QgsGPXFeatureIterator::close()
+{
+  if (mClosed)
+    return false;
+
+  P->mDataMutex.unlock();
+  mClosed = true;
+  return true;
+}

Added: branches/threading-branch/src/providers/gpx/qgsgpxfeatureiterator.h
===================================================================
--- branches/threading-branch/src/providers/gpx/qgsgpxfeatureiterator.h	                        (rev 0)
+++ branches/threading-branch/src/providers/gpx/qgsgpxfeatureiterator.h	2010-07-07 18:37:02 UTC (rev 13897)
@@ -0,0 +1,59 @@
+#ifndef QGSGPXFEATUREITERATOR_H
+#define QGSGPXFEATUREITERATOR_H
+
+
+#include "qgsvectordataprovider.h"
+
+#include "gpsdata.h"
+
+class QgsGPXProvider;
+
+
+class QgsGPXFeatureIterator : public QgsVectorDataProviderIterator
+{
+public:
+  QgsGPXFeatureIterator( QgsGPXProvider* p,
+                         QgsAttributeList fetchAttributes,
+                         QgsRectangle rect,
+                         bool fetchGeometry,
+                         bool useIntersect );
+
+  ~QgsGPXFeatureIterator();
+
+  //! 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:
+
+  bool nextWaypoint(QgsFeature& feature);
+  bool nextRoute(QgsFeature& feature);
+  bool nextTrack(QgsFeature& feature);
+
+  /**
+   * Check to see if the point is withn the selection
+   * rectangle
+   * @param x X value of point
+   * @param y Y value of point
+   * @return True if point is within the rectangle
+   */
+  bool boundsCheck( double x, double y );
+
+  bool boundsCheckRect( double xmin, double ymin, double xmax, double ymax );
+
+  //! Current waypoint iterator
+  QgsGPSData::WaypointIterator mWptIter;
+  //! Current route iterator
+  QgsGPSData::RouteIterator mRteIter;
+  //! Current track iterator
+  QgsGPSData::TrackIterator mTrkIter;
+
+  QgsGPXProvider* P;
+};
+
+#endif // QGSGPXFEATUREITERATOR_H

Modified: branches/threading-branch/src/providers/gpx/qgsgpxprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/gpx/qgsgpxprovider.cpp	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/gpx/qgsgpxprovider.cpp	2010-07-07 18:37:02 UTC (rev 13897)
@@ -42,6 +42,7 @@
 #include "qgscoordinatereferencesystem.h"
 #include "qgsrectangle.h"
 #include "qgsgpxprovider.h"
+#include "qgsgpxfeatureiterator.h"
 #include "gpsdata.h"
 #include "qgslogger.h"
 
@@ -94,9 +95,6 @@
   attributeFields[URLNameAttr] = QgsField( attr[URLNameAttr], QVariant::String, "text" );
   mFileName = uri.left( fileNameEnd );
 
-  // set the selection rectangle to null
-  mSelectionRectangle = 0;
-
   // parse the file
   data = QgsGPSData::getData( mFileName );
   if ( data == 0 )
@@ -111,7 +109,6 @@
 QgsGPXProvider::~QgsGPXProvider()
 {
   QgsGPSData::releaseData( mFileName );
-  delete mSelectionRectangle;
 }
 
 
@@ -127,288 +124,23 @@
          QgsVectorDataProvider::ChangeAttributeValues;
 }
 
-bool QgsGPXProvider::nextFeature( QgsFeature& feature )
+QgsFeatureIterator QgsGPXProvider::getFeatures( QgsAttributeList fetchAttributes,
+                                                QgsRectangle rect,
+                                                bool fetchGeometry,
+                                                bool useIntersect )
 {
-  feature.setValid( false );
-  bool result = false;
+  return QgsFeatureIterator( new QgsGPXFeatureIterator(this, fetchAttributes, rect, fetchGeometry, useIntersect) );
+}
 
-  QgsAttributeList::const_iterator iter;
-
-  if ( mFeatureType == WaypointType )
+bool QgsGPXProvider::nextFeature( QgsFeature& feature )
+{
+  if (mOldApiIter.nextFeature(feature))
+    return true;
+  else
   {
-    // go through the list of waypoints and return the first one that is in
-    // the bounds rectangle
-    for ( ; mWptIter != data->waypointsEnd(); ++mWptIter )
-    {
-      const QgsWaypoint* wpt;
-      wpt = &( *mWptIter );
-      if ( boundsCheck( wpt->lon, wpt->lat ) )
-      {
-        feature.setFeatureId( wpt->id );
-        result = true;
-
-        // some wkb voodoo
-        if ( mFetchGeom )
-        {
-          char* geo = new char[21];
-          std::memset( geo, 0, 21 );
-          geo[0] = QgsApplication::endian();
-          geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBPoint;
-          std::memcpy( geo + 5, &wpt->lon, sizeof( double ) );
-          std::memcpy( geo + 13, &wpt->lat, sizeof( double ) );
-          feature.setGeometryAndOwnership(( unsigned char * )geo, sizeof( wkbPoint ) );
-        }
-        feature.setValid( true );
-
-        // add attributes if they are wanted
-        for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
-        {
-          switch ( *iter )
-          {
-            case NameAttr:
-              feature.addAttribute( NameAttr, QVariant( wpt->name ) );
-              break;
-            case EleAttr:
-              if ( wpt->ele != -std::numeric_limits<double>::max() )
-                feature.addAttribute( EleAttr, QVariant( wpt->ele ) );
-              break;
-            case SymAttr:
-              feature.addAttribute( SymAttr, QVariant( wpt->sym ) );
-              break;
-            case CmtAttr:
-              feature.addAttribute( CmtAttr, QVariant( wpt->cmt ) );
-              break;
-            case DscAttr:
-              feature.addAttribute( DscAttr, QVariant( wpt->desc ) );
-              break;
-            case SrcAttr:
-              feature.addAttribute( SrcAttr, QVariant( wpt->src ) );
-              break;
-            case URLAttr:
-              feature.addAttribute( URLAttr, QVariant( wpt->url ) );
-              break;
-            case URLNameAttr:
-              feature.addAttribute( URLNameAttr, QVariant( wpt->urlname ) );
-              break;
-          }
-        }
-
-        ++mWptIter;
-        break;
-      }
-    }
+    mOldApiIter.close(); // make sure to unlock the layer
+    return false;
   }
-
-  else if ( mFeatureType == RouteType )
-  {
-    // go through the routes and return the first one that is in the bounds
-    // rectangle
-    for ( ; mRteIter != data->routesEnd(); ++mRteIter )
-    {
-      const QgsRoute* rte;
-      rte = &( *mRteIter );
-
-      if ( rte->points.size() == 0 )
-        continue;
-      const QgsRectangle& b( *mSelectionRectangle );
-      if (( rte->xMax >= b.xMinimum() ) && ( rte->xMin <= b.xMaximum() ) &&
-          ( rte->yMax >= b.yMinimum() ) && ( rte->yMin <= b.yMaximum() ) )
-      {
-        // some wkb voodoo
-        int nPoints = rte->points.size();
-        char* geo = new char[9 + 16 * nPoints];
-        std::memset( geo, 0, 9 + 16 * nPoints );
-        geo[0] = QgsApplication::endian();
-        geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString;
-        std::memcpy( geo + 5, &nPoints, 4 );
-        for ( uint i = 0; i < rte->points.size(); ++i )
-        {
-          std::memcpy( geo + 9 + 16 * i, &rte->points[i].lon, sizeof( double ) );
-          std::memcpy( geo + 9 + 16 * i + 8, &rte->points[i].lat, sizeof( double ) );
-        }
-
-        //create QgsGeometry and use it for intersection test
-        //if geometry is to be fetched, it is attached to the feature, otherwise we delete it
-        QgsGeometry* theGeometry = new QgsGeometry();
-        theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * nPoints );
-        bool intersection = theGeometry->intersects( b );//use geos for precise intersection test
-
-        if ( !intersection )
-        {
-          delete theGeometry;
-        }
-        else
-        {
-          if ( mFetchGeom )
-          {
-            feature.setGeometry( theGeometry );
-          }
-          else
-          {
-            delete theGeometry;
-          }
-          feature.setFeatureId( rte->id );
-          result = true;
-          feature.setValid( true );
-
-          // add attributes if they are wanted
-          for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
-          {
-            switch ( *iter )
-            {
-              case NameAttr:
-                feature.addAttribute( NameAttr, QVariant( rte->name ) );
-                break;
-              case NumAttr:
-                if ( rte->number != std::numeric_limits<int>::max() )
-                  feature.addAttribute( NumAttr, QVariant( rte->number ) );
-                break;
-              case CmtAttr:
-                feature.addAttribute( CmtAttr, QVariant( rte->cmt ) );
-                break;
-              case DscAttr:
-                feature.addAttribute( DscAttr, QVariant( rte->desc ) );
-                break;
-              case SrcAttr:
-                feature.addAttribute( SrcAttr, QVariant( rte->src ) );
-                break;
-              case URLAttr:
-                feature.addAttribute( URLAttr, QVariant( rte->url ) );
-                break;
-              case URLNameAttr:
-                feature.addAttribute( URLNameAttr, QVariant( rte->urlname ) );
-                break;
-            }
-          }
-
-          ++mRteIter;
-          break;
-
-        }
-
-        //++mRteIter;
-        //xbreak;
-      }
-    }
-  }
-
-  else if ( mFeatureType == TrackType )
-  {
-    // go through the tracks and return the first one that is in the bounds
-    // rectangle
-    for ( ; mTrkIter != data->tracksEnd(); ++mTrkIter )
-    {
-      const QgsTrack* trk;
-      trk = &( *mTrkIter );
-
-      QgsDebugMsg( QString( "GPX feature track segments: %1" ).arg( trk->segments.size() ) );
-      if ( trk->segments.size() == 0 )
-        continue;
-
-      // A track consists of several segments. Add all those segments into one.
-      int totalPoints = 0;;
-      for ( std::vector<QgsTrackSegment>::size_type i = 0; i < trk->segments.size(); i ++ )
-      {
-        totalPoints += trk->segments[i].points.size();
-      }
-      if ( totalPoints == 0 )
-        continue;
-      QgsDebugMsg( "GPX feature track total points: " + QString::number( totalPoints ) );
-      const QgsRectangle& b( *mSelectionRectangle );
-      if (( trk->xMax >= b.xMinimum() ) && ( trk->xMin <= b.xMaximum() ) &&
-          ( trk->yMax >= b.yMinimum() ) && ( trk->yMin <= b.yMaximum() ) )
-      {
-        // some wkb voodoo
-        char* geo = new char[9 + 16 * totalPoints];
-        if ( !geo )
-        {
-          QgsDebugMsg( "Too large track!!!" );
-          return false;
-        }
-        std::memset( geo, 0, 9 + 16 * totalPoints );
-        geo[0] = QgsApplication::endian();
-        geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString;
-        std::memcpy( geo + 5, &totalPoints, 4 );
-
-        int thisPoint = 0;
-        for ( std::vector<QgsTrackSegment>::size_type k = 0; k < trk->segments.size(); k++ )
-        {
-          int nPoints = trk->segments[k].points.size();
-          for ( int i = 0; i < nPoints; ++i )
-          {
-            std::memcpy( geo + 9 + 16 * thisPoint,     &trk->segments[k].points[i].lon, sizeof( double ) );
-            std::memcpy( geo + 9 + 16 * thisPoint + 8, &trk->segments[k].points[i].lat, sizeof( double ) );
-            thisPoint++;
-          }
-        }
-
-        //create QgsGeometry and use it for intersection test
-        //if geometry is to be fetched, it is attached to the feature, otherwise we delete it
-        QgsGeometry* theGeometry = new QgsGeometry();
-        theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * totalPoints );
-        bool intersection = theGeometry->intersects( b );//use geos for precise intersection test
-
-        if ( !intersection ) //no intersection, delete geometry and move on
-        {
-          delete theGeometry;
-        }
-        else //intersection
-        {
-          if ( mFetchGeom )
-          {
-            feature.setGeometry( theGeometry );
-          }
-          else
-          {
-            delete theGeometry;
-          }
-          feature.setFeatureId( trk->id );
-          result = true;
-
-          feature.setValid( true );
-
-          // add attributes if they are wanted
-          for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
-          {
-            switch ( *iter )
-            {
-              case NameAttr:
-                feature.addAttribute( NameAttr, QVariant( trk->name ) );
-                break;
-              case NumAttr:
-                if ( trk->number != std::numeric_limits<int>::max() )
-                  feature.addAttribute( NumAttr, QVariant( trk->number ) );
-                break;
-              case CmtAttr:
-                feature.addAttribute( CmtAttr, QVariant( trk->cmt ) );
-                break;
-              case DscAttr:
-                feature.addAttribute( DscAttr, QVariant( trk->desc ) );
-                break;
-              case SrcAttr:
-                feature.addAttribute( SrcAttr, QVariant( trk->src ) );
-                break;
-              case URLAttr:
-                feature.addAttribute( URLAttr, QVariant( trk->url ) );
-                break;
-              case URLNameAttr:
-                feature.addAttribute( URLNameAttr, QVariant( trk->urlname ) );
-                break;
-            }
-          }
-
-          ++mTrkIter;
-          break;
-        }
-      }
-
-    }
-  }
-  if ( result )
-  {
-    feature.setValid( true );
-  }
-  return result;
 }
 
 void QgsGPXProvider::select( QgsAttributeList fetchAttributes,
@@ -416,21 +148,13 @@
                              bool fetchGeometry,
                              bool useIntersect )
 {
-  delete mSelectionRectangle;
-  mSelectionRectangle = 0;
+  mOldApiIter = getFeatures( fetchAttributes, rect, fetchGeometry, useIntersect );
+}
 
-  if ( rect.isEmpty() )
-  {
-    mSelectionRectangle = new QgsRectangle( extent() );
-  }
-  else
-  {
-    mSelectionRectangle = new QgsRectangle( rect );
-  }
-  mAttributesToFetch = fetchAttributes;
-  mFetchGeom = fetchGeometry;
 
-  rewind();
+void QgsGPXProvider::rewind()
+{
+  mOldApiIter.rewind();
 }
 
 
@@ -487,17 +211,6 @@
 }
 
 
-void QgsGPXProvider::rewind()
-{
-  if ( mFeatureType == WaypointType )
-    mWptIter = data->waypointsBegin();
-  else if ( mFeatureType == RouteType )
-    mRteIter = data->routesBegin();
-  else if ( mFeatureType == TrackType )
-    mTrkIter = data->tracksBegin();
-}
-
-
 bool QgsGPXProvider::isValid()
 {
   return mValid;
@@ -506,6 +219,7 @@
 
 bool QgsGPXProvider::addFeatures( QgsFeatureList & flist )
 {
+  QMutexLocker locker(&mDataMutex);
 
   // add all the features
   for ( QgsFeatureList::iterator iter = flist.begin();
@@ -699,6 +413,8 @@
 
 bool QgsGPXProvider::deleteFeatures( const QgsFeatureIds & id )
 {
+  QMutexLocker locker(&mDataMutex);
+
   if ( mFeatureType == WaypointType )
     data->removeWaypoints( id );
   else if ( mFeatureType == RouteType )
@@ -718,6 +434,8 @@
 
 bool QgsGPXProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
 {
+  QMutexLocker locker(&mDataMutex);
+
   QgsChangedAttributesMap::const_iterator aIter = attr_map.begin();
   if ( mFeatureType == WaypointType )
   {
@@ -822,20 +540,7 @@
 }
 
 
-/**
- * Check to see if the point is within the selection rectangle
- */
-bool QgsGPXProvider::boundsCheck( double x, double y )
-{
-  bool inBounds = ((( x <= mSelectionRectangle->xMaximum() ) &&
-                    ( x >= mSelectionRectangle->xMinimum() ) ) &&
-                   (( y <= mSelectionRectangle->yMaximum() ) &&
-                    ( y >= mSelectionRectangle->yMinimum() ) ) );
-  QString hit = inBounds ? "true" : "false";
-  return inBounds;
-}
 
-
 QString QgsGPXProvider::name() const
 {
   return GPX_KEY;

Modified: branches/threading-branch/src/providers/gpx/qgsgpxprovider.h
===================================================================
--- branches/threading-branch/src/providers/gpx/qgsgpxprovider.h	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/gpx/qgsgpxprovider.h	2010-07-07 18:37:02 UTC (rev 13897)
@@ -21,6 +21,7 @@
 #include "qgsvectordataprovider.h"
 #include "gpsdata.h"
 
+#include <QMutex>
 
 class QgsFeature;
 class QgsField;
@@ -70,6 +71,11 @@
      */
     virtual bool nextFeature( QgsFeature& feature );
 
+    virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                            QgsRectangle rect = QgsRectangle(),
+                                            bool fetchGeometry = true,
+                                            bool useIntersect = false );
+
     /**
      * Get feature type.
      * @return int representing the feature type
@@ -150,16 +156,7 @@
     /** Adds one feature (used by addFeatures()) */
     bool addFeature( QgsFeature& f );
 
-    /**
-     * Check to see if the point is withn the selection
-     * rectangle
-     * @param x X value of point
-     * @param y Y value of point
-     * @return True if point is within the rectangle
-     */
-    bool boundsCheck( double x, double y );
 
-
   private:
 
     QgsGPSData* data;
@@ -174,25 +171,12 @@
                      CmtAttr, DscAttr, SrcAttr, URLAttr, URLNameAttr
                  };
     static const char* attr[];
-    //! Current selection rectangle
-    QgsRectangle *mSelectionRectangle;
+
     bool mValid;
     long mNumberFeatures;
 
-    //! Current waypoint iterator
-    QgsGPSData::WaypointIterator mWptIter;
-    //! Current route iterator
-    QgsGPSData::RouteIterator mRteIter;
-    //! Current track iterator
-    QgsGPSData::TrackIterator mTrkIter;
+    friend class QgsGPXFeatureIterator;
+    QgsFeatureIterator mOldApiIter;
 
-    struct wkbPoint
-    {
-      char byteOrder;
-      unsigned wkbType;
-      double x;
-      double y;
-    };
-    wkbPoint mWKBpt;
-
+    QMutex mDataMutex;
 };

Modified: branches/threading-branch/src/providers/memory/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/providers/memory/CMakeLists.txt	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/memory/CMakeLists.txt	2010-07-07 18:37:02 UTC (rev 13897)
@@ -1,5 +1,5 @@
 
-SET (MEMORY_SRCS qgsmemoryprovider.cpp)
+SET (MEMORY_SRCS qgsmemoryprovider.cpp qgsmemoryfeatureiterator.cpp)
 
 INCLUDE_DIRECTORIES(
   .

Added: branches/threading-branch/src/providers/memory/qgsmemoryfeatureiterator.cpp
===================================================================
--- branches/threading-branch/src/providers/memory/qgsmemoryfeatureiterator.cpp	                        (rev 0)
+++ branches/threading-branch/src/providers/memory/qgsmemoryfeatureiterator.cpp	2010-07-07 18:37:02 UTC (rev 13897)
@@ -0,0 +1,150 @@
+#include "qgsmemoryfeatureiterator.h"
+#include "qgsmemoryprovider.h"
+
+#include "qgsgeometry.h"
+#include "qgslogger.h"
+#include "qgsspatialindex.h"
+
+// used from provider:
+// - mSpatialIndex
+// - mFeatures
+
+QgsMemoryFeatureIterator::QgsMemoryFeatureIterator( QgsMemoryProvider* p,
+                                                    QgsAttributeList fetchAttributes,
+                                                    QgsRectangle rect,
+                                                    bool fetchGeometry,
+                                                    bool useIntersect )
+ : QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect),
+   P(p),
+   mRectGeom( NULL )
+{
+
+  P->mDataMutex.lock();
+
+  mRectGeom = QgsGeometry::fromRect( rect );
+
+  // if there's spatial index, use it!
+  // (but don't use it when selection rect is not specified)
+  if ( P->mSpatialIndex && !mRect.isEmpty() )
+  {
+    mSelectUsingSpatialIndex = true;
+    mSelectSI_Features = P->mSpatialIndex->intersects( rect );
+    QgsDebugMsg( "Features returned by spatial index: " + QString::number( mSelectSI_Features.count() ) );
+  }
+  else
+  {
+    mSelectUsingSpatialIndex = false;
+    mSelectSI_Features.clear();
+  }
+
+  rewind();
+}
+
+QgsMemoryFeatureIterator::~QgsMemoryFeatureIterator()
+{
+  close();
+}
+
+bool QgsMemoryFeatureIterator::nextFeature(QgsFeature& feature)
+{
+  if (mClosed)
+    return false;
+
+  feature.setValid( false );
+  bool hasFeature = false;
+
+  // option 1: using spatial index
+  if ( mSelectUsingSpatialIndex )
+  {
+    while ( mSelectSI_Iterator != mSelectSI_Features.end() )
+    {
+      // do exact check in case we're doing intersection
+      if ( mUseIntersect )
+      {
+        if ( P->mFeatures[*mSelectSI_Iterator].geometry()->intersects( mRectGeom ) )
+          hasFeature = true;
+      }
+      else
+        hasFeature = true;
+
+      if ( hasFeature )
+        break;
+
+      mSelectSI_Iterator++;
+    }
+
+    // copy feature
+    if ( hasFeature )
+    {
+      feature = P->mFeatures[*mSelectSI_Iterator];
+      mSelectSI_Iterator++;
+    }
+    return hasFeature;
+  }
+
+  // option 2: not using spatial index
+  while ( mSelectIterator != P->mFeatures.end() )
+  {
+    if ( mRect.isEmpty() )
+    {
+      // selection rect empty => using all features
+      hasFeature = true;
+    }
+    else
+    {
+      if ( mUseIntersect )
+      {
+        // using exact test when checking for intersection
+        if ( mSelectIterator->geometry()->intersects( mRectGeom ) )
+          hasFeature = true;
+      }
+      else
+      {
+        // check just bounding box against rect when not using intersection
+        if ( mSelectIterator->geometry()->boundingBox().intersects( mRect ) )
+          hasFeature = true;
+      }
+    }
+
+    if ( hasFeature )
+      break;
+
+    mSelectIterator++;
+  }
+
+  // copy feature
+  if ( hasFeature )
+  {
+    feature = mSelectIterator.value();
+    mSelectIterator++;
+    feature.setValid( true );
+  }
+
+  return hasFeature;
+}
+
+bool QgsMemoryFeatureIterator::rewind()
+{
+  if (mClosed)
+    return false;
+
+  if ( mSelectUsingSpatialIndex )
+    mSelectSI_Iterator = mSelectSI_Features.begin();
+  else
+    mSelectIterator = P->mFeatures.begin();
+
+  return true;
+}
+
+bool QgsMemoryFeatureIterator::close()
+{
+  if (mClosed)
+    return false;
+
+  delete mRectGeom;
+  mRectGeom = NULL;
+
+  P->mDataMutex.unlock();
+
+  return true;
+}

Added: branches/threading-branch/src/providers/memory/qgsmemoryfeatureiterator.h
===================================================================
--- branches/threading-branch/src/providers/memory/qgsmemoryfeatureiterator.h	                        (rev 0)
+++ branches/threading-branch/src/providers/memory/qgsmemoryfeatureiterator.h	2010-07-07 18:37:02 UTC (rev 13897)
@@ -0,0 +1,43 @@
+#ifndef QGSMEMORYFEATUREITERATOR_H
+#define QGSMEMORYFEATUREITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+class QgsMemoryProvider;
+
+typedef QMap<int, QgsFeature> QgsFeatureMap;
+
+
+class QgsMemoryFeatureIterator : public QgsVectorDataProviderIterator
+{
+public:
+  QgsMemoryFeatureIterator( QgsMemoryProvider* p,
+                            QgsAttributeList fetchAttributes,
+                            QgsRectangle rect,
+                            bool fetchGeometry,
+                            bool useIntersect );
+
+  ~QgsMemoryFeatureIterator();
+
+  //! 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:
+  QgsMemoryProvider* P;
+
+  QgsGeometry* mRectGeom;
+
+  QgsFeatureMap::iterator mSelectIterator;
+  bool mSelectUsingSpatialIndex;
+  QList<int> mSelectSI_Features;
+  QList<int>::iterator mSelectSI_Iterator;
+};
+
+
+#endif // QGSMEMORYFEATUREITERATOR_H

Modified: branches/threading-branch/src/providers/memory/qgsmemoryprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/memory/qgsmemoryprovider.cpp	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/memory/qgsmemoryprovider.cpp	2010-07-07 18:37:02 UTC (rev 13897)
@@ -14,6 +14,7 @@
  ***************************************************************************/
 
 #include "qgsmemoryprovider.h"
+#include "qgsmemoryfeatureiterator.h"
 
 #include "qgsfeature.h"
 #include "qgsfield.h"
@@ -28,7 +29,6 @@
 
 QgsMemoryProvider::QgsMemoryProvider( QString uri )
     : QgsVectorDataProvider( uri ),
-    mSelectRectGeom( NULL ),
     mSpatialIndex( NULL )
 {
   if ( uri == "Point" )
@@ -58,7 +58,6 @@
 QgsMemoryProvider::~QgsMemoryProvider()
 {
   delete mSpatialIndex;
-  delete mSelectRectGeom;
 }
 
 QString QgsMemoryProvider::storageType() const
@@ -66,79 +65,23 @@
   return "Memory storage";
 }
 
-bool QgsMemoryProvider::nextFeature( QgsFeature& feature )
+QgsFeatureIterator QgsMemoryProvider::getFeatures( QgsAttributeList fetchAttributes,
+                                                   QgsRectangle rect,
+                                                   bool fetchGeometry,
+                                                   bool useIntersect )
 {
-  feature.setValid( false );
-  bool hasFeature = false;
+  return QgsFeatureIterator( new QgsMemoryFeatureIterator(this, fetchAttributes, rect, fetchGeometry, useIntersect) );
+}
 
-  // option 1: using spatial index
-  if ( mSelectUsingSpatialIndex )
+bool QgsMemoryProvider::nextFeature( QgsFeature& feature )
+{
+  if (mOldApiIter.nextFeature(feature))
+    return true;
+  else
   {
-    while ( mSelectSI_Iterator != mSelectSI_Features.end() )
-    {
-      // do exact check in case we're doing intersection
-      if ( mSelectUseIntersect )
-      {
-        if ( mFeatures[*mSelectSI_Iterator].geometry()->intersects( mSelectRectGeom ) )
-          hasFeature = true;
-      }
-      else
-        hasFeature = true;
-
-      if ( hasFeature )
-        break;
-
-      mSelectSI_Iterator++;
-    }
-
-    // copy feature
-    if ( hasFeature )
-    {
-      feature = mFeatures[*mSelectSI_Iterator];
-      mSelectSI_Iterator++;
-    }
-    return hasFeature;
+    mOldApiIter.close(); // make sure to unlock the layer
+    return false;
   }
-
-  // option 2: not using spatial index
-  while ( mSelectIterator != mFeatures.end() )
-  {
-    if ( mSelectRect.isEmpty() )
-    {
-      // selection rect empty => using all features
-      hasFeature = true;
-    }
-    else
-    {
-      if ( mSelectUseIntersect )
-      {
-        // using exact test when checking for intersection
-        if ( mSelectIterator->geometry()->intersects( mSelectRectGeom ) )
-          hasFeature = true;
-      }
-      else
-      {
-        // check just bounding box against rect when not using intersection
-        if ( mSelectIterator->geometry()->boundingBox().intersects( mSelectRect ) )
-          hasFeature = true;
-      }
-    }
-
-    if ( hasFeature )
-      break;
-
-    mSelectIterator++;
-  }
-
-  // copy feature
-  if ( hasFeature )
-  {
-    feature = mSelectIterator.value();
-    mSelectIterator++;
-    feature.setValid( true );
-  }
-
-  return hasFeature;
 }
 
 
@@ -147,6 +90,8 @@
                                      bool fetchGeometry,
                                      QgsAttributeList fetchAttributes )
 {
+  QMutexLocker locker(&mDataMutex);
+
   feature.setValid( false );
   QgsFeatureMap::iterator it = mFeatures.find( featureId );
 
@@ -164,36 +109,12 @@
                                 bool fetchGeometry,
                                 bool useIntersect )
 {
-  mSelectAttrs = fetchAttributes;
-  mSelectRect = rect;
-  delete mSelectRectGeom;
-  mSelectRectGeom = QgsGeometry::fromRect( rect );
-  mSelectGeometry = fetchGeometry;
-  mSelectUseIntersect = useIntersect;
-
-  // if there's spatial index, use it!
-  // (but don't use it when selection rect is not specified)
-  if ( mSpatialIndex && !mSelectRect.isEmpty() )
-  {
-    mSelectUsingSpatialIndex = true;
-    mSelectSI_Features = mSpatialIndex->intersects( rect );
-    QgsDebugMsg( "Features returned by spatial index: " + QString::number( mSelectSI_Features.count() ) );
-  }
-  else
-  {
-    mSelectUsingSpatialIndex = false;
-    mSelectSI_Features.clear();
-  }
-
-  rewind();
+  mOldApiIter = getFeatures( fetchAttributes, rect, fetchGeometry, useIntersect );
 }
 
 void QgsMemoryProvider::rewind()
 {
-  if ( mSelectUsingSpatialIndex )
-    mSelectSI_Iterator = mSelectSI_Features.begin();
-  else
-    mSelectIterator = mFeatures.begin();
+  mOldApiIter.rewind();
 }
 
 
@@ -237,6 +158,8 @@
 
 bool QgsMemoryProvider::addFeatures( QgsFeatureList & flist )
 {
+  QMutexLocker locker(&mDataMutex);
+
   // TODO: sanity checks of fields and geometries
   for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
   {
@@ -259,6 +182,8 @@
 
 bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds & id )
 {
+  QMutexLocker locker(&mDataMutex);
+
   for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
   {
     QgsFeatureMap::iterator fit = mFeatures.find( *it );
@@ -281,6 +206,8 @@
 
 bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
 {
+  QMutexLocker locker(&mDataMutex);
+
   for ( QList<QgsField>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
   {
     switch ( it->type() )
@@ -305,6 +232,8 @@
 
 bool QgsMemoryProvider::deleteAttributes( const QgsAttributeIds& attributes )
 {
+  QMutexLocker locker(&mDataMutex);
+
   for ( QgsAttributeIds::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
     mFields.remove( *it );
   return true;
@@ -312,6 +241,8 @@
 
 bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
 {
+  QMutexLocker locker(&mDataMutex);
+
   for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
   {
     QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
@@ -327,6 +258,8 @@
 
 bool QgsMemoryProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
 {
+  QMutexLocker locker(&mDataMutex);
+
   for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
   {
     QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
@@ -351,6 +284,8 @@
 
 bool QgsMemoryProvider::createSpatialIndex()
 {
+  QMutexLocker locker(&mDataMutex);
+
   if ( !mSpatialIndex )
   {
     mSpatialIndex = new QgsSpatialIndex();

Modified: branches/threading-branch/src/providers/memory/qgsmemoryprovider.h
===================================================================
--- branches/threading-branch/src/providers/memory/qgsmemoryprovider.h	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/memory/qgsmemoryprovider.h	2010-07-07 18:37:02 UTC (rev 13897)
@@ -15,6 +15,7 @@
 
 #include "qgsvectordataprovider.h"
 
+#include <QMutex>
 
 typedef QMap<int, QgsFeature> QgsFeatureMap;
 
@@ -58,6 +59,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
@@ -194,17 +200,11 @@
     QgsFeatureMap mFeatures;
     int mNextFeatureId;
 
-    // selection
-    QgsAttributeList mSelectAttrs;
-    QgsRectangle mSelectRect;
-    QgsGeometry* mSelectRectGeom;
-    bool mSelectGeometry, mSelectUseIntersect;
-    QgsFeatureMap::iterator mSelectIterator;
-    bool mSelectUsingSpatialIndex;
-    QList<int> mSelectSI_Features;
-    QList<int>::iterator mSelectSI_Iterator;
-
     // indexing
     QgsSpatialIndex* mSpatialIndex;
 
+    friend class QgsMemoryFeatureIterator;
+    QgsFeatureIterator mOldApiIter;
+
+    QMutex mDataMutex;
 };

Modified: branches/threading-branch/src/providers/spatialite/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/providers/spatialite/CMakeLists.txt	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/spatialite/CMakeLists.txt	2010-07-07 18:37:02 UTC (rev 13897)
@@ -2,7 +2,7 @@
 ########################################################
 # Files
 
-SET(SPATIALITE_SRCS qgsspatialiteprovider.cpp)
+SET(SPATIALITE_SRCS qgsspatialiteprovider.cpp qgsspatialitefeatureiterator.cpp)
 
 SET(SPATIALITE_MOC_HDRS qgsspatialiteprovider.h)
 

Added: branches/threading-branch/src/providers/spatialite/qgsspatialitefeatureiterator.cpp
===================================================================
--- branches/threading-branch/src/providers/spatialite/qgsspatialitefeatureiterator.cpp	                        (rev 0)
+++ branches/threading-branch/src/providers/spatialite/qgsspatialitefeatureiterator.cpp	2010-07-07 18:37:02 UTC (rev 13897)
@@ -0,0 +1,275 @@
+#include "qgsspatialitefeatureiterator.h"
+#include "qgsspatialiteprovider.h"
+
+#include <sqlite3.h>
+
+#include "qgslogger.h"
+
+// from provider:
+// - sqliteHandle
+// - mIndexTable, mIndexGeometry
+// - mGeometryColumn, mTableName
+// - mSubsetString, mVShapeBased
+// - spatialIndexRTree, spatialIndexMbrCache
+// - field()
+
+QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteProvider* p,
+                                                            QgsAttributeList fetchAttributes,
+                                                            QgsRectangle rect,
+                                                            bool fetchGeometry,
+                                                            bool useIntersect )
+ : QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect),
+   P(p),
+   sqliteStatement( NULL )
+{
+  P->mHandleMutex.lock();
+
+  // preparing the SQL statement
+
+  QString sql = "SELECT ROWID";
+  for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it )
+  {
+    const QgsField & fld = P->field( *it );
+    const QString & fieldname = fld.name();
+    sql += "," + QgsSpatiaLiteProvider::quotedIdentifier( fieldname );
+  }
+  if ( fetchGeometry )
+  {
+    sql += QString( ", AsBinary(%1)" ).arg( QgsSpatiaLiteProvider::quotedIdentifier( P->mGeometryColumn ) );
+  }
+  sql += QString( " FROM %1" ).arg( QgsSpatiaLiteProvider::quotedIdentifier( P->mTableName ) );
+
+  QString whereClause;
+
+  if ( !rect.isEmpty() )
+  {
+    // some kind of MBR spatial filtering is required
+    whereClause = " WHERE ";
+    if ( useIntersect )
+    {
+      // we are requested to evaluate a true INTERSECT relationship
+      QString mbr = QString( "%1, %2, %3, %4" ).
+                    arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
+                    arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
+                    arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
+      whereClause += QString( "Intersects(%1, BuildMbr(%2)) AND " ).arg( QgsSpatiaLiteProvider::quotedIdentifier( P->mGeometryColumn ) ).arg( mbr );
+    }
+    if ( P->mVShapeBased )
+    {
+      // handling a VirtualShape layer
+      QString mbr = QString( "%1, %2, %3, %4" ).
+                    arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
+                    arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
+                    arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
+      whereClause += QString( "MbrIntersects(%1, BuildMbr(%2))" ).arg( QgsSpatiaLiteProvider::quotedIdentifier( P->mGeometryColumn ) ).arg( mbr );
+    }
+    else
+    {
+      if ( P->spatialIndexRTree )
+      {
+        // using the RTree spatial index
+        QString mbrFilter = QString( "xmin <= %1 AND " ).arg( QString::number( rect.xMaximum(), 'f', 6 ) );
+        mbrFilter += QString( "xmax >= %1 AND " ).arg( QString::number( rect.xMinimum(), 'f', 6 ) );
+        mbrFilter += QString( "ymin <= %1 AND " ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
+        mbrFilter += QString( "ymax >= %1" ).arg( QString::number( rect.yMinimum(), 'f', 6 ) );
+        QString idxName = QString( "idx_%1_%2" ).arg( P->mIndexTable ).arg( P->mIndexGeometry );
+        whereClause += QString( "ROWID IN (SELECT pkid FROM %1 WHERE %2)" ).arg( QgsSpatiaLiteProvider::quotedIdentifier( idxName ) ).arg( mbrFilter );
+      }
+      else if ( P->spatialIndexMbrCache )
+      {
+        // using the MbrCache spatial index
+        QString mbr = QString( "%1, %2, %3, %4" ).
+                      arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
+                      arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
+                      arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
+        QString idxName = QString( "cache_%1_%2" ).arg( P->mIndexTable ).arg( P->mIndexGeometry );
+        whereClause += QString( "ROWID IN (SELECT rowid FROM %1 WHERE mbr = FilterMbrIntersects(%2))" ).arg( QgsSpatiaLiteProvider::quotedIdentifier( idxName ) ).arg( mbr );
+      }
+      else
+      {
+        // using simple MBR filtering
+        QString mbr = QString( "%1, %2, %3, %4" ).
+                      arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
+                      arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
+                      arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
+        whereClause += QString( "MbrIntersects(%1, BuildMbr(%2))" ).arg( QgsSpatiaLiteProvider::quotedIdentifier( P->mGeometryColumn ) ).arg( mbr );
+      }
+    }
+  }
+
+  if ( !whereClause.isEmpty() )
+    sql += whereClause;
+
+  if ( !P->mSubsetString.isEmpty() )
+  {
+    if ( !whereClause.isEmpty() )
+    {
+      sql += " AND ";
+    }
+    else
+    {
+      sql += " WHERE ";
+    }
+    sql += "( " + P->mSubsetString + ")";
+  }
+
+  if ( sqlite3_prepare_v2( P->sqliteHandle, sql.toUtf8().constData(), -1, &sqliteStatement, NULL ) != SQLITE_OK )
+  {
+    // some error occurred
+    QgsDebugMsg( QString( "SQLite error: %1\n\nSQL: %2" ).arg( sql ).arg( QString::fromUtf8( sqlite3_errmsg( P->sqliteHandle ) ) ) );
+    sqliteStatement = NULL;
+  }
+
+}
+
+QgsSpatiaLiteFeatureIterator::~QgsSpatiaLiteFeatureIterator()
+{
+  close();
+}
+
+bool QgsSpatiaLiteFeatureIterator::nextFeature(QgsFeature& feature)
+{
+  if (mClosed)
+    return false;
+
+  feature.setValid( false );
+
+  if ( sqliteStatement == NULL )
+  {
+    QgsDebugMsg( "Invalid current SQLite statement" );
+    return false;
+  }
+
+  int ret = sqlite3_step( sqliteStatement );
+  if ( ret == SQLITE_DONE )
+  {
+    // there are no more rows to fetch - we can stop looping destroying the SQLite statement
+    sqlite3_finalize( sqliteStatement );
+    sqliteStatement = NULL;
+    return false;
+  }
+  if ( ret == SQLITE_ROW )
+  {
+    // one valid row has been fetched from the result set
+    if ( !mFetchGeometry )
+    {
+      // no geometry was required
+      feature.setGeometryAndOwnership( 0, 0 );
+    }
+
+    feature.clearAttributeMap();
+
+    int ic;
+    int n_columns = sqlite3_column_count( sqliteStatement );
+    for ( ic = 0; ic < n_columns; ic++ )
+    {
+      if ( ic == 0 )
+      {
+        // first column always contains the ROWID
+        feature.setFeatureId( sqlite3_column_int( sqliteStatement, ic ) );
+      }
+      else
+      {
+        // iterate attributes
+        bool fetched = false;
+        int nAttr = 1;
+        for ( QgsAttributeList::const_iterator it = mFetchAttributes.constBegin(); it != mFetchAttributes.constEnd(); it++ )
+        {
+          if ( nAttr == ic )
+          {
+            // ok, this one is the corresponding attribure
+            if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_INTEGER )
+            {
+              // INTEGER value
+              feature.addAttribute( *it, sqlite3_column_int( sqliteStatement, ic ) );
+              fetched = true;
+            }
+            else if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_FLOAT )
+            {
+              // DOUBLE value
+              feature.addAttribute( *it, sqlite3_column_double( sqliteStatement, ic ) );
+              fetched = true;
+            }
+            else if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_TEXT )
+            {
+              // TEXT value
+              const char *txt = ( const char * ) sqlite3_column_text( sqliteStatement, ic );
+              QString str = QString::fromUtf8( txt );
+              feature.addAttribute( *it, str );
+              fetched = true;
+            }
+            else
+            {
+              // assuming NULL
+              feature.addAttribute( *it, QVariant( QString::null ) );
+              fetched = true;
+            }
+          }
+          nAttr++;
+        }
+        if ( fetched )
+        {
+          continue;
+        }
+        if ( mFetchGeometry )
+        {
+          QString geoCol = QString( "AsBinary(%1)" ).arg( QgsSpatiaLiteProvider::quotedIdentifier( P->mGeometryColumn ) );
+          if ( strcasecmp( geoCol.toUtf8().constData(), sqlite3_column_name( sqliteStatement, ic ) ) == 0 )
+          {
+            if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_BLOB )
+            {
+              const void *blob = sqlite3_column_blob( sqliteStatement, ic );
+              size_t blob_size = sqlite3_column_bytes( sqliteStatement, ic );
+              unsigned char *featureGeom = new unsigned char[blob_size + 1];
+              memset( featureGeom, '\0', blob_size + 1 );
+              memcpy( featureGeom, blob, blob_size );
+              feature.setGeometryAndOwnership( featureGeom, blob_size + 1 );
+            }
+            else
+            {
+              // NULL geometry
+              feature.setGeometryAndOwnership( 0, 0 );
+            }
+          }
+        }
+      }
+    }
+  }
+  else
+  {
+    // some unexpected error occurred
+    QgsDebugMsg( QString( "sqlite3_step() error: %1" ).arg( QString::fromUtf8( sqlite3_errmsg( P->sqliteHandle ) ) ) );
+    sqlite3_finalize( sqliteStatement );
+    sqliteStatement = NULL;
+    return false;
+  }
+
+  feature.setValid( true );
+  return true;
+
+}
+
+bool QgsSpatiaLiteFeatureIterator::rewind()
+{
+  if (mClosed)
+    return false;
+
+  if ( sqliteStatement )
+  {
+    sqlite3_finalize( sqliteStatement );
+    sqliteStatement = NULL;
+  }
+
+  return true;
+}
+
+bool QgsSpatiaLiteFeatureIterator::close()
+{
+  if (mClosed)
+    return false;
+
+  P->mHandleMutex.unlock();
+
+  mClosed = true;
+  return true;
+}

Added: branches/threading-branch/src/providers/spatialite/qgsspatialitefeatureiterator.h
===================================================================
--- branches/threading-branch/src/providers/spatialite/qgsspatialitefeatureiterator.h	                        (rev 0)
+++ branches/threading-branch/src/providers/spatialite/qgsspatialitefeatureiterator.h	2010-07-07 18:37:02 UTC (rev 13897)
@@ -0,0 +1,42 @@
+#ifndef QGSSPATIALITEFEATUREITERATOR_H
+#define QGSSPATIALITEFEATUREITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+class QgsSpatiaLiteProvider;
+
+extern "C"
+{
+#include <sqlite3.h>
+}
+
+class QgsSpatiaLiteFeatureIterator : public QgsVectorDataProviderIterator
+{
+public:
+  QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteProvider* p,
+                                QgsAttributeList fetchAttributes,
+                                QgsRectangle rect,
+                                bool fetchGeometry,
+                                bool useIntersect );
+
+  ~QgsSpatiaLiteFeatureIterator();
+
+  //! 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:
+  QgsSpatiaLiteProvider* P;
+
+  /**
+    * SQLite statement handle
+   */
+  sqlite3_stmt *sqliteStatement;
+};
+
+#endif // QGSSPATIALITEFEATUREITERATOR_H

Modified: branches/threading-branch/src/providers/spatialite/qgsspatialiteprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/spatialite/qgsspatialiteprovider.cpp	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/spatialite/qgsspatialiteprovider.cpp	2010-07-07 18:37:02 UTC (rev 13897)
@@ -24,6 +24,7 @@
 #include <qgscoordinatereferencesystem.h>
 
 #include "qgsspatialiteprovider.h"
+#include "qgsspatialitefeatureiterator.h"
 
 #include "qgslogger.h"
 
@@ -40,7 +41,6 @@
     : QgsVectorDataProvider( uri )
     , geomType( QGis::WKBUnknown )
     , sqliteHandle( NULL )
-    , sqliteStatement( NULL )
     , mSrid( -1 )
     , spatialIndexRTree( false )
     , spatialIndexMbrCache( false )
@@ -217,6 +217,8 @@
 
 bool QgsSpatiaLiteProvider::featureAtId( int featureId, QgsFeature & feature, bool fetchGeometry, QgsAttributeList fetchAttributes )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   sqlite3_stmt *stmt = NULL;
 
   feature.setValid( false );
@@ -253,7 +255,7 @@
   if ( ret == SQLITE_ROW )
   {
     // one valid row has been fetched from the result set
-    if ( !mFetchGeom )
+    if ( !fetchGeometry )
     {
       // no geometry was required
       feature.setGeometryAndOwnership( 0, 0 );
@@ -313,7 +315,7 @@
         {
           continue;
         }
-        if ( mFetchGeom )
+        if ( fetchGeometry )
         {
           QString geoCol = QString( "AsBinary(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
           if ( strcasecmp( geoCol.toUtf8().constData(), sqlite3_column_name( stmt, ic ) ) == 0 )
@@ -351,129 +353,6 @@
   return true;
 }
 
-bool QgsSpatiaLiteProvider::nextFeature( QgsFeature & feature )
-{
-  feature.setValid( false );
-  if ( !valid )
-  {
-    QgsDebugMsg( "Read attempt on an invalid SpatiaLite data source" );
-    return false;
-  }
-
-  if ( sqliteStatement == NULL )
-  {
-    QgsDebugMsg( "Invalid current SQLite statement" );
-    return false;
-  }
-
-  int ret = sqlite3_step( sqliteStatement );
-  if ( ret == SQLITE_DONE )
-  {
-    // there are no more rows to fetch - we can stop looping destroying the SQLite statement
-    sqlite3_finalize( sqliteStatement );
-    sqliteStatement = NULL;
-    return false;
-  }
-  if ( ret == SQLITE_ROW )
-  {
-    // one valid row has been fetched from the result set
-    if ( !mFetchGeom )
-    {
-      // no geometry was required
-      feature.setGeometryAndOwnership( 0, 0 );
-    }
-
-    feature.clearAttributeMap();
-
-    int ic;
-    int n_columns = sqlite3_column_count( sqliteStatement );
-    for ( ic = 0; ic < n_columns; ic++ )
-    {
-      if ( ic == 0 )
-      {
-        // first column always contains the ROWID
-        feature.setFeatureId( sqlite3_column_int( sqliteStatement, ic ) );
-      }
-      else
-      {
-        // iterate attributes
-        bool fetched = false;
-        int nAttr = 1;
-        for ( QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin(); it != mAttributesToFetch.constEnd(); it++ )
-        {
-          if ( nAttr == ic )
-          {
-            // ok, this one is the corresponding attribure
-            if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_INTEGER )
-            {
-              // INTEGER value
-              feature.addAttribute( *it, sqlite3_column_int( sqliteStatement, ic ) );
-              fetched = true;
-            }
-            else if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_FLOAT )
-            {
-              // DOUBLE value
-              feature.addAttribute( *it, sqlite3_column_double( sqliteStatement, ic ) );
-              fetched = true;
-            }
-            else if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_TEXT )
-            {
-              // TEXT value
-              const char *txt = ( const char * ) sqlite3_column_text( sqliteStatement, ic );
-              QString str = QString::fromUtf8( txt );
-              feature.addAttribute( *it, str );
-              fetched = true;
-            }
-            else
-            {
-              // assuming NULL
-              feature.addAttribute( *it, QVariant( QString::null ) );
-              fetched = true;
-            }
-          }
-          nAttr++;
-        }
-        if ( fetched )
-        {
-          continue;
-        }
-        if ( mFetchGeom )
-        {
-          QString geoCol = QString( "AsBinary(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
-          if ( strcasecmp( geoCol.toUtf8().constData(), sqlite3_column_name( sqliteStatement, ic ) ) == 0 )
-          {
-            if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_BLOB )
-            {
-              const void *blob = sqlite3_column_blob( sqliteStatement, ic );
-              size_t blob_size = sqlite3_column_bytes( sqliteStatement, ic );
-              unsigned char *featureGeom = new unsigned char[blob_size + 1];
-              memset( featureGeom, '\0', blob_size + 1 );
-              memcpy( featureGeom, blob, blob_size );
-              feature.setGeometryAndOwnership( featureGeom, blob_size + 1 );
-            }
-            else
-            {
-              // NULL geometry
-              feature.setGeometryAndOwnership( 0, 0 );
-            }
-          }
-        }
-      }
-    }
-  }
-  else
-  {
-    // some unexpected error occurred
-    QgsDebugMsg( QString( "sqlite3_step() error: %1" ).arg( QString::fromUtf8( sqlite3_errmsg( sqliteHandle ) ) ) );
-    sqlite3_finalize( sqliteStatement );
-    sqliteStatement = NULL;
-    return false;
-  }
-
-  feature.setValid( true );
-  return true;
-}
-
 QString QgsSpatiaLiteProvider::subsetString()
 {
   return mSubsetString;
@@ -481,6 +360,8 @@
 
 bool QgsSpatiaLiteProvider::setSubsetString( QString theSQL )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   QString prevSubsetString = mSubsetString;
   mSubsetString = theSQL;
 
@@ -505,118 +386,46 @@
   return false;
 }
 
-void QgsSpatiaLiteProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
+QgsFeatureIterator QgsSpatiaLiteProvider::getFeatures( QgsAttributeList fetchAttributes,
+                                                       QgsRectangle rect,
+                                                       bool fetchGeometry,
+                                                       bool useIntersect )
 {
-// preparing the SQL statement
-
   if ( !valid )
   {
     QgsDebugMsg( "Read attempt on an invalid SpatiaLite data source" );
-    return;
+    return QgsFeatureIterator();
   }
 
-  if ( sqliteStatement != NULL )
-  {
-    // finalizing the current SQLite statement
-    sqlite3_finalize( sqliteStatement );
-    sqliteStatement = NULL;
-  }
+  return QgsFeatureIterator( new QgsSpatiaLiteFeatureIterator(this, fetchAttributes, rect, fetchGeometry, useIntersect) );
+}
 
-  QString sql = "SELECT ROWID";
-  for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it )
-  {
-    const QgsField & fld = field( *it );
-    const QString & fieldname = fld.name();
-    sql += "," + quotedIdentifier( fieldname );
-  }
-  if ( fetchGeometry )
-  {
-    sql += QString( ", AsBinary(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
-  }
-  sql += QString( " FROM %1" ).arg( quotedIdentifier( mTableName ) );
 
-  QString whereClause;
+void QgsSpatiaLiteProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
+{
+  mOldApiIter = getFeatures( fetchAttributes, rect, fetchGeometry, useIntersect );
+}
 
-  if ( !rect.isEmpty() )
+bool QgsSpatiaLiteProvider::nextFeature( QgsFeature & feature )
+{
+  if ( !valid )
   {
-    // some kind of MBR spatial filtering is required
-    whereClause = " WHERE ";
-    if ( useIntersect )
-    {
-      // we are requested to evaluate a true INTERSECT relationship
-      QString mbr = QString( "%1, %2, %3, %4" ).
-                    arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
-                    arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
-                    arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
-      whereClause += QString( "Intersects(%1, BuildMbr(%2)) AND " ).arg( quotedIdentifier( mGeometryColumn ) ).arg( mbr );
-    }
-    if ( mVShapeBased )
-    {
-      // handling a VirtualShape layer
-      QString mbr = QString( "%1, %2, %3, %4" ).
-                    arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
-                    arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
-                    arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
-      whereClause += QString( "MbrIntersects(%1, BuildMbr(%2))" ).arg( quotedIdentifier( mGeometryColumn ) ).arg( mbr );
-    }
-    else
-    {
-      if ( spatialIndexRTree )
-      {
-        // using the RTree spatial index
-        QString mbrFilter = QString( "xmin <= %1 AND " ).arg( QString::number( rect.xMaximum(), 'f', 6 ) );
-        mbrFilter += QString( "xmax >= %1 AND " ).arg( QString::number( rect.xMinimum(), 'f', 6 ) );
-        mbrFilter += QString( "ymin <= %1 AND " ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
-        mbrFilter += QString( "ymax >= %1" ).arg( QString::number( rect.yMinimum(), 'f', 6 ) );
-        QString idxName = QString( "idx_%1_%2" ).arg( mIndexTable ).arg( mIndexGeometry );
-        whereClause += QString( "ROWID IN (SELECT pkid FROM %1 WHERE %2)" ).arg( quotedIdentifier( idxName ) ).arg( mbrFilter );
-      }
-      else if ( spatialIndexMbrCache )
-      {
-        // using the MbrCache spatial index
-        QString mbr = QString( "%1, %2, %3, %4" ).
-                      arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
-                      arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
-                      arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
-        QString idxName = QString( "cache_%1_%2" ).arg( mIndexTable ).arg( mIndexGeometry );
-        whereClause += QString( "ROWID IN (SELECT rowid FROM %1 WHERE mbr = FilterMbrIntersects(%2))" ).arg( quotedIdentifier( idxName ) ).arg( mbr );
-      }
-      else
-      {
-        // using simple MBR filtering
-        QString mbr = QString( "%1, %2, %3, %4" ).
-                      arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
-                      arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
-                      arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
-        whereClause += QString( "MbrIntersects(%1, BuildMbr(%2))" ).arg( quotedIdentifier( mGeometryColumn ) ).arg( mbr );
-      }
-    }
+    QgsDebugMsg( "Read attempt on an invalid SpatiaLite data source" );
+    return false;
   }
 
-  if ( !whereClause.isEmpty() )
-    sql += whereClause;
-
-  if ( !mSubsetString.isEmpty() )
+  if (mOldApiIter.nextFeature(feature))
+    return true;
+  else
   {
-    if ( !whereClause.isEmpty() )
-    {
-      sql += " AND ";
-    }
-    else
-    {
-      sql += " WHERE ";
-    }
-    sql += "( " + mSubsetString + ")";
+    mOldApiIter.close(); // make sure to unlock the layer
+    return false;
   }
+}
 
-  mFetchGeom = fetchGeometry;
-  mAttributesToFetch = fetchAttributes;
-  if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &sqliteStatement, NULL ) != SQLITE_OK )
-  {
-    // some error occurred
-    QgsDebugMsg( QString( "SQLite error: %1\n\nSQL: %2" ).arg( sql ).arg( QString::fromUtf8( sqlite3_errmsg( sqliteHandle ) ) ) );
-    sqliteStatement = NULL;
-  }
+void QgsSpatiaLiteProvider::rewind()
+{
+  mOldApiIter.rewind();
 }
 
 
@@ -657,16 +466,6 @@
 }
 
 
-void QgsSpatiaLiteProvider::rewind()
-{
-  if ( sqliteStatement )
-  {
-    sqlite3_finalize( sqliteStatement );
-    sqliteStatement = NULL;
-  }
-  loadFields();
-}
-
 QgsCoordinateReferenceSystem QgsSpatiaLiteProvider::crs()
 {
   QgsCoordinateReferenceSystem srs;
@@ -700,6 +499,8 @@
 // Returns the minimum value of an attribute
 QVariant QgsSpatiaLiteProvider::minimumValue( int index )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   int ret;
   int i;
   char **results;
@@ -756,6 +557,8 @@
 // Returns the maximum value of an attribute
 QVariant QgsSpatiaLiteProvider::maximumValue( int index )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   int ret;
   int i;
   char **results;
@@ -812,6 +615,8 @@
 // Returns the list of unique values of an attribute
 void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueValues, int limit )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   sqlite3_stmt *stmt = NULL;
   QString sql;
   QString txt;
@@ -886,6 +691,8 @@
 
 bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   sqlite3_stmt *stmt = NULL;
   char *errMsg = NULL;
   bool toCommit = false;
@@ -1053,6 +860,8 @@
 
 bool QgsSpatiaLiteProvider::deleteFeatures( const QgsFeatureIds & id )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   sqlite3_stmt *stmt = NULL;
   char *errMsg = NULL;
   bool toCommit = false;
@@ -1130,6 +939,8 @@
 
 bool QgsSpatiaLiteProvider::addAttributes( const QList<QgsField> &attributes )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   char *errMsg = NULL;
   bool toCommit = false;
   QString sql;
@@ -1186,6 +997,8 @@
 
 bool QgsSpatiaLiteProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   char *errMsg = NULL;
   bool toCommit = false;
   QString sql;
@@ -1281,6 +1094,8 @@
 
 bool QgsSpatiaLiteProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
 {
+  QMutexLocker locker(&mHandleMutex);
+
   sqlite3_stmt *stmt = NULL;
   char *errMsg = NULL;
   bool toCommit = false;
@@ -1373,12 +1188,9 @@
 
 void QgsSpatiaLiteProvider::closeDb()
 {
-// trying to close the SQLite DB
-  if ( sqliteStatement )
-  {
-    sqlite3_finalize( sqliteStatement );
-    sqliteStatement = NULL;
-  }
+  mOldApiIter.close();
+
+  // trying to close the SQLite DB
   if ( handle )
   {
     SqliteHandles::closeDb( handle );
@@ -1485,13 +1297,13 @@
   }
 }
 
-QString QgsSpatiaLiteProvider::quotedIdentifier( QString id ) const
+QString QgsSpatiaLiteProvider::quotedIdentifier( QString id )
 {
   id.replace( "\"", "\"\"" );
   return id.prepend( "\"" ).append( "\"" );
 }
 
-QString QgsSpatiaLiteProvider::quotedValue( QString value ) const
+QString QgsSpatiaLiteProvider::quotedValue( QString value )
 {
   if ( value.isNull() )
     return "NULL";

Modified: branches/threading-branch/src/providers/spatialite/qgsspatialiteprovider.h
===================================================================
--- branches/threading-branch/src/providers/spatialite/qgsspatialiteprovider.h	2010-07-07 14:15:53 UTC (rev 13896)
+++ branches/threading-branch/src/providers/spatialite/qgsspatialiteprovider.h	2010-07-07 18:37:02 UTC (rev 13897)
@@ -28,6 +28,8 @@
 #include <fstream>
 #include <set>
 
+#include <QMutex>
+
 class QgsFeature;
 class QgsField;
 
@@ -100,6 +102,11 @@
      */
     virtual bool nextFeature( QgsFeature & feature );
 
+    virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+                                            QgsRectangle rect = QgsRectangle(),
+                                            bool fetchGeometry = true,
+                                            bool useIntersect = false );
+
     /** Get the feature type. This corresponds to
      * WKBPoint,
      * WKBLineString,
@@ -314,10 +321,6 @@
      */
     sqlite3 *sqliteHandle;
     /**
-      * SQLite statement handle
-     */
-    sqlite3_stmt *sqliteStatement;
-    /**
      * String used to define a subset of the layer
      */
     QString mSubsetString;
@@ -356,8 +359,7 @@
     */
     //void sqliteOpen();
     void closeDb();
-    QString quotedIdentifier( QString id ) const;
-    QString quotedValue( QString value ) const;
+
     bool checkLayerType();
     bool getGeometryDetails();
     bool getTableGeometryDetails();
@@ -366,6 +368,9 @@
     bool getSridDetails();
     bool getTableSummary();
 
+    static QString quotedIdentifier( QString id );
+    static QString quotedValue( QString value );
+
   public:
     class SqliteHandles
     {
@@ -404,4 +409,9 @@
      * sqlite3 handles pointer
      */
     SqliteHandles *handle;
+
+    friend class QgsSpatiaLiteFeatureIterator;
+    QgsFeatureIterator mOldApiIter;
+
+    QMutex mHandleMutex;
 };



More information about the QGIS-commit mailing list