[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