[QGIS Commit] r13881 - in branches/threading-branch: python/core
src/analysis/interpolation src/core src/gui src/providers/ogr
src/providers/osm src/providers/postgres
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Sat Jul 3 12:50:45 EDT 2010
Author: wonder
Date: 2010-07-03 16:50:45 +0000 (Sat, 03 Jul 2010)
New Revision: 13881
Added:
branches/threading-branch/src/core/qgsvectorlayeriterator.cpp
branches/threading-branch/src/core/qgsvectorlayeriterator.h
branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.cpp
branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.h
branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.cpp
branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.h
Modified:
branches/threading-branch/python/core/qgsvectordataprovider.sip
branches/threading-branch/python/core/qgsvectorlayer.sip
branches/threading-branch/src/analysis/interpolation/qgsinterpolator.cpp
branches/threading-branch/src/core/CMakeLists.txt
branches/threading-branch/src/core/qgsvectordataprovider.cpp
branches/threading-branch/src/core/qgsvectordataprovider.h
branches/threading-branch/src/core/qgsvectorlayer.cpp
branches/threading-branch/src/core/qgsvectorlayer.h
branches/threading-branch/src/gui/qgsmaptip.cpp
branches/threading-branch/src/providers/ogr/CMakeLists.txt
branches/threading-branch/src/providers/ogr/qgsogrprovider.cpp
branches/threading-branch/src/providers/ogr/qgsogrprovider.h
branches/threading-branch/src/providers/osm/osmprovider.cpp
branches/threading-branch/src/providers/postgres/CMakeLists.txt
branches/threading-branch/src/providers/postgres/qgspostgresprovider.cpp
branches/threading-branch/src/providers/postgres/qgspostgresprovider.h
Log:
Introduced new API for access to vector layers and vector data providers.
New API implemented so far only for OGR and PostGIS providers - both using locking to control read access to data from multiple threads.
Modified: branches/threading-branch/python/core/qgsvectordataprovider.sip
===================================================================
--- branches/threading-branch/python/core/qgsvectordataprovider.sip 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/python/core/qgsvectordataprovider.sip 2010-07-03 16:50:45 UTC (rev 13881)
@@ -1,4 +1,39 @@
+typedef QList<int> QgsAttributeList;
+
+class QgsFeatureIterator
+{
+%TypeHeaderCode
+#include <qgsvectordataprovider.h>
+%End
+
+public:
+ //! construct invalid iterator
+ QgsFeatureIterator();
+ //! construct an iterator for iterating an instance of vector data provider
+ //QgsFeatureIterator(QgsVectorDataProviderIterator* iter);
+ //! construct an iterator for iterating an instance of vector layer (data provider + uncommitted data)
+ //QgsFeatureIterator(VectorLayerIterator* layerIter);
+ //! copy constructor copies the provider iterator, increases ref.count
+ QgsFeatureIterator(const QgsFeatureIterator& fi);
+ //! destructor deletes the provider iterator if it has no more references
+ ~QgsFeatureIterator();
+
+ // TODO? QgsFeatureIterator& operator=(const QgsFeatureIterator& other);
+
+ bool nextFeature(QgsFeature& f);
+ bool rewind();
+ bool close();
+
+ //! find out whether the iterator is still valid or closed already
+ bool isClosed();
+
+};
+
+bool operator== (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2);
+bool operator!= (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2);
+
+
class QgsVectorDataProvider : QgsDataProvider
{
%TypeHeaderCode
@@ -82,7 +117,17 @@
*/
virtual long updateFeatureCount();
- /**
+ /**
+ * Start iterating over features of the vector data provider.
+ * For new code, consider using this method instead of select/nextFeature combo.
+ * @note Added in v1.6
+ */
+ virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+ QgsRectangle rect = QgsRectangle(),
+ bool fetchGeometry = true,
+ bool useIntersect = false );
+
+ /**
* Gets the feature at the given feature ID.
* @param featureId id of the feature
* @param feature feature which will receive the data
Modified: branches/threading-branch/python/core/qgsvectorlayer.sip
===================================================================
--- branches/threading-branch/python/core/qgsvectorlayer.sip 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/python/core/qgsvectorlayer.sip 2010-07-03 16:50:45 UTC (rev 13881)
@@ -132,9 +132,9 @@
void setUsingRendererV2(bool usingRendererV2);
/** Draw layer with renderer V2. Added in QGIS 1.4 */
- void drawRendererV2( QgsRenderContext& rendererContext, bool labeling );
+ void drawRendererV2( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi );
/** Draw layer with renderer V2 using symbol levels. Added in QGIS 1.4 */
- void drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling );
+ void drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi );
/** Returns point, line or polygon */
QGis::GeometryType geometryType() const;
@@ -207,6 +207,15 @@
bool nextFeature(QgsFeature& feature);
+ /**
+ * Start iterating over features of the layer.
+ * For new code, consider using this method instead of select/nextFeature combo.
+ * @note Added in v1.6
+ */
+ QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+ QgsRectangle rect = QgsRectangle(),
+ bool fetchGeometry = true,
+ bool useIntersect = false );
/**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
@return true in case of success*/
Modified: branches/threading-branch/src/analysis/interpolation/qgsinterpolator.cpp
===================================================================
--- branches/threading-branch/src/analysis/interpolation/qgsinterpolator.cpp 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/analysis/interpolation/qgsinterpolator.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -16,7 +16,7 @@
***************************************************************************/
#include "qgsinterpolator.h"
-#include "qgsvectordataprovider.h"
+#include "qgsvectorlayer.h"
#include "qgsgeometry.h"
#ifndef Q_OS_MACX
#include <cmath>
Modified: branches/threading-branch/src/core/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/core/CMakeLists.txt 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/CMakeLists.txt 2010-07-03 16:50:45 UTC (rev 13881)
@@ -87,6 +87,7 @@
qgsvectordataprovider.cpp
qgsvectorfilewriter.cpp
qgsvectorlayer.cpp
+ qgsvectorlayeriterator.cpp
qgsvectorlayerundocommand.cpp
qgsvectoroverlay.cpp
Modified: branches/threading-branch/src/core/qgsvectordataprovider.cpp
===================================================================
--- branches/threading-branch/src/core/qgsvectordataprovider.cpp 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/qgsvectordataprovider.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -25,6 +25,114 @@
#include "qgsfield.h"
#include "qgslogger.h"
+
+
+QgsVectorDataProviderIterator::QgsVectorDataProviderIterator(QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
+ : mFetchAttributes(fetchAttributes),
+ mFetchGeometry(fetchGeometry),
+ mRect(rect),
+ mUseIntersect(useIntersect),
+ refs(0),
+ mClosed(false)
+{
+}
+
+QgsVectorDataProviderIterator::~QgsVectorDataProviderIterator()
+{
+}
+
+void QgsVectorDataProviderIterator::ref()
+{
+ refs++;
+ QgsDebugMsg("ADDED REF: "+QString::number(refs));
+}
+void QgsVectorDataProviderIterator::deref()
+{
+ refs--;
+ QgsDebugMsg("REMOVED REF: "+QString::number(refs));
+ if (!refs)
+ delete this;
+}
+
+////////
+
+QgsFeatureIterator::QgsFeatureIterator()
+ : provIter(NULL)
+{
+ QgsDebugMsg("CREATED INVALID ITER");
+}
+
+QgsFeatureIterator::QgsFeatureIterator(QgsVectorDataProviderIterator* iter)
+ : provIter(iter)
+{
+ QgsDebugMsg("CREATED GOOD ITER");
+ if (iter)
+ iter->ref();
+}
+
+QgsFeatureIterator::QgsFeatureIterator(const QgsFeatureIterator& fi)
+ : provIter(fi.provIter)
+{
+ QgsDebugMsg("CREATED COPIED ITER");
+ if (provIter)
+ provIter->ref();
+}
+
+QgsFeatureIterator::~QgsFeatureIterator()
+{
+ QgsDebugMsg("DELETING ITER");
+ if (provIter)
+ provIter->deref();
+}
+
+QgsFeatureIterator& QgsFeatureIterator::operator=(const QgsFeatureIterator& other)
+{
+ if (this != &other)
+ {
+ if (provIter)
+ provIter->deref();
+ provIter = other.provIter;
+ if (provIter)
+ provIter->ref();
+ }
+ return *this;
+}
+
+bool QgsFeatureIterator::nextFeature(QgsFeature& f)
+{
+ return provIter ? provIter->nextFeature(f) : false;
+}
+
+bool QgsFeatureIterator::rewind()
+{
+ return provIter ? provIter->rewind() : false;
+}
+
+bool QgsFeatureIterator::close()
+{
+ return provIter ? provIter->close() : false;
+}
+
+bool QgsFeatureIterator::isClosed()
+{
+ return provIter ? provIter->mClosed : true;
+}
+
+
+bool operator== (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)
+{
+ return (fi1.provIter == fi2.provIter);
+}
+bool operator!= (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)
+{
+ return !(fi1 == fi2);
+}
+
+////////////
+
QgsVectorDataProvider::QgsVectorDataProvider( QString uri )
: QgsDataProvider( uri ),
mCacheMinMaxDirty( true ),
@@ -49,6 +157,11 @@
return -1;
}
+QgsFeatureIterator QgsVectorDataProvider::getFeatures( QgsAttributeList, QgsRectangle, bool, bool)
+{
+ return QgsFeatureIterator();
+}
+
bool QgsVectorDataProvider::featureAtId( int featureId,
QgsFeature& feature,
bool fetchGeometry,
Modified: branches/threading-branch/src/core/qgsvectordataprovider.h
===================================================================
--- branches/threading-branch/src/core/qgsvectordataprovider.h 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/qgsvectordataprovider.h 2010-07-03 16:50:45 UTC (rev 13881)
@@ -25,10 +25,88 @@
//QGIS Includes
#include "qgis.h"
#include "qgsdataprovider.h"
-#include "qgsvectorlayer.h"
+#include "qgsfeature.h"
#include "qgsfield.h"
+#include "qgsrectangle.h"
+typedef QList<int> QgsAttributeList;
+typedef QSet<int> QgsFeatureIds;
+typedef QSet<int> QgsAttributeIds;
+
+
/** \ingroup core
+ * Internal feature iterator to be implemented within data providers
+ */
+class QgsVectorDataProviderIterator
+{
+public:
+ //! base class constructor - stores the iteration parameters
+ QgsVectorDataProviderIterator(QgsAttributeList fetchAttributes = QgsAttributeList(),
+ QgsRectangle rect = QgsRectangle(),
+ bool fetchGeometry = true,
+ bool useIntersect = false );
+
+ //! destructor makes sure that the iterator is closed properly
+ virtual ~QgsVectorDataProviderIterator();
+
+ //! fetch next feature, return true on success
+ virtual bool nextFeature(QgsFeature& f) = 0;
+ //! reset the iterator to the starting position
+ virtual bool rewind() = 0;
+ //! end of iterating: free the resources / lock
+ virtual bool close() = 0;
+
+protected:
+ QgsAttributeList mFetchAttributes;
+ bool mFetchGeometry;
+ QgsRectangle mRect;
+ bool mUseIntersect;
+
+ bool mClosed;
+
+ // reference counting (to allow seamless copying of QgsFeatureIterator instances)
+ int refs;
+ void ref(); // add reference
+ void deref(); // remove reference, delete if refs == 0
+ friend class QgsFeatureIterator;
+};
+
+/**
+ * \ingroup core
+ * Wrapper for iterator of features from vector data provider or vector layer
+ */
+class QgsFeatureIterator
+{
+public:
+ //! construct invalid iterator
+ QgsFeatureIterator();
+ //! construct an iterator for iterating an instance of vector data provider
+ QgsFeatureIterator(QgsVectorDataProviderIterator* iter);
+ //! construct an iterator for iterating an instance of vector layer (data provider + uncommitted data)
+ //QgsFeatureIterator(VectorLayerIterator* layerIter);
+ //! copy constructor copies the provider iterator, increases ref.count
+ QgsFeatureIterator(const QgsFeatureIterator& fi);
+ //! destructor deletes the provider iterator if it has no more references
+ ~QgsFeatureIterator();
+
+ QgsFeatureIterator& operator=(const QgsFeatureIterator& other);
+
+ bool nextFeature(QgsFeature& f);
+ bool rewind();
+ bool close();
+
+ //! find out whether the iterator is still valid or closed already
+ bool isClosed();
+
+ friend bool operator== (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2);
+ friend bool operator!= (const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2);
+
+protected:
+ QgsVectorDataProviderIterator* provIter;
+};
+
+
+/** \ingroup core
* This is the base class for vector data providers.
*
* Data providers abstract the retrieval and writing (where supported)
@@ -113,6 +191,16 @@
virtual long updateFeatureCount();
/**
+ * Start iterating over features of the vector data provider.
+ * For new code, consider using this method instead of select/nextFeature combo.
+ * @note Added in v1.6
+ */
+ virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+ QgsRectangle rect = QgsRectangle(),
+ bool fetchGeometry = true,
+ bool useIntersect = false );
+
+ /**
* Gets the feature at the given feature ID.
* @param featureId of the feature to be returned
* @param feature which will receive the data
Modified: branches/threading-branch/src/core/qgsvectorlayer.cpp
===================================================================
--- branches/threading-branch/src/core/qgsvectorlayer.cpp 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/qgsvectorlayer.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -67,6 +67,7 @@
#include "qgssinglesymbolrenderer.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsvectordataprovider.h"
+#include "qgsvectorlayeriterator.h"
#include "qgsvectorlayerundocommand.h"
#include "qgsvectoroverlay.h"
#include "qgsmaplayerregistry.h"
@@ -106,8 +107,7 @@
mUsingRendererV2( false ),
mLabel( 0 ),
mLabelOn( false ),
- mVertexMarkerOnlyForSelection( false ),
- mFetching( false )
+ mVertexMarkerOnlyForSelection( false )
{
mActions = new QgsAttributeAction;
@@ -689,7 +689,7 @@
return ptr;
}
-void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool labeling )
+void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi )
{
QSettings settings;
bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
@@ -697,7 +697,7 @@
mRendererV2->startRender( rendererContext, this );
QgsFeature fet;
- while ( nextFeature( fet ) )
+ while ( fi.nextFeature( fet ) )
{
try
{
@@ -730,7 +730,7 @@
}
}
-void QgsVectorLayer::drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling )
+void QgsVectorLayer::drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi )
{
QHash< QgsSymbolV2*, QList<QgsFeature> > features; // key = symbol, value = array of features
@@ -751,7 +751,7 @@
// 1. fetch features
QgsFeature fet;
- while ( nextFeature( fet ) )
+ while ( fi.nextFeature( fet ) )
{
if ( rendererContext.renderingStopped() )
{
@@ -872,13 +872,15 @@
}
}
- select( attributes, rendererContext.extent() );
+ QgsFeatureIterator fi = getFeatures( attributes, rendererContext.extent() );
if ( mRendererV2->usingSymbolLevels() )
- drawRendererV2Levels( rendererContext, labeling );
+ drawRendererV2Levels( rendererContext, labeling, fi );
else
- drawRendererV2( rendererContext, labeling );
+ drawRendererV2( rendererContext, labeling, fi );
+ fi.close();
+
return true;
}
@@ -929,11 +931,11 @@
}
}
- select( attributes, rendererContext.extent() );
+ QgsFeatureIterator fi = getFeatures( attributes, rendererContext.extent() );
try
{
- while ( nextFeature( fet ) )
+ while ( fi.nextFeature( fet ) )
{
if ( rendererContext.renderingStopped() )
@@ -1360,7 +1362,7 @@
return res;
}
-void QgsVectorLayer::updateFeatureAttributes( QgsFeature &f, bool all )
+void QgsVectorLayer::updateFeatureAttributes( QgsFeature &f, const QgsAttributeList& fetchAttributes )
{
// do not update when we aren't in editing mode
if ( !mEditable )
@@ -1381,7 +1383,7 @@
// null/add all attributes that were added, but don't exist in the feature yet
for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ )
- if ( !map.contains( it.key() ) && ( all || mFetchAttributes.contains( it.key() ) ) )
+ if ( !map.contains( it.key() ) && fetchAttributes.contains( it.key() ) )
f.changeAttribute( it.key(), QVariant( QString::null ) );
}
@@ -1394,165 +1396,25 @@
void QgsVectorLayer::select( QgsAttributeList attributes, QgsRectangle rect, bool fetchGeometries, bool useIntersect )
{
- if ( !mDataProvider )
- return;
-
- mFetching = true;
- mFetchRect = rect;
- mFetchAttributes = attributes;
- mFetchGeometry = fetchGeometries;
-
- mFetchConsidered = mDeletedFeatureIds;
-
- if ( mEditable )
- {
- mFetchAddedFeaturesIt = mAddedFeatures.begin();
- mFetchChangedGeomIt = mChangedGeometries.begin();
- }
-
- //look in the normal features of the provider
- if ( mFetchAttributes.size() > 0 )
- {
- if ( mEditable )
- {
- // fetch only available field from provider
- mFetchProvAttributes.clear();
- for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); it++ )
- {
- if ( !mUpdatedFields.contains( *it ) || mAddedAttributeIds.contains( *it ) )
- continue;
-
- mFetchProvAttributes << *it;
- }
-
- mDataProvider->select( mFetchProvAttributes, rect, fetchGeometries, useIntersect );
- }
- else
- mDataProvider->select( mFetchAttributes, rect, fetchGeometries, useIntersect );
- }
- else
- {
- mDataProvider->select( QgsAttributeList(), rect, fetchGeometries, useIntersect );
- }
+ if (!mOldApiIter.isClosed())
+ mOldApiIter.close();
+ mOldApiIter = getFeatures( attributes, rect, fetchGeometries, useIntersect );
}
bool QgsVectorLayer::nextFeature( QgsFeature &f )
{
- if ( !mFetching )
- return false;
+ return mOldApiIter.nextFeature(f);
+}
- if ( mEditable )
- {
- if ( !mFetchRect.isEmpty() )
- {
- // check if changed geometries are in rectangle
- for ( ; mFetchChangedGeomIt != mChangedGeometries.end(); mFetchChangedGeomIt++ )
- {
- int fid = mFetchChangedGeomIt.key();
-
- if ( mFetchConsidered.contains( fid ) )
- // skip deleted features
- continue;
-
- mFetchConsidered << fid;
-
- if ( !mFetchChangedGeomIt->intersects( mFetchRect ) )
- // skip changed geometries not in rectangle and don't check again
- continue;
-
- f.setFeatureId( fid );
- f.setValid( true );
-
- if ( mFetchGeometry )
- f.setGeometry( mFetchChangedGeomIt.value() );
-
- if ( mFetchAttributes.size() > 0 )
- {
- if ( fid < 0 )
- {
- // fid<0 => in mAddedFeatures
- bool found = false;
-
- for ( QgsFeatureList::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); it++ )
- {
- if ( fid != it->id() )
- {
- found = true;
- f.setAttributeMap( it->attributeMap() );
- break;
- }
- }
-
- if ( !found )
- QgsDebugMsg( QString( "No attributes for the added feature %1 found" ).arg( f.id() ) );
- }
- else
- {
- // retrieve attributes from provider
- QgsFeature tmp;
- mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
- updateFeatureAttributes( tmp );
- f.setAttributeMap( tmp.attributeMap() );
- }
- }
-
- // return complete feature
- mFetchChangedGeomIt++;
- return true;
- }
-
- // no more changed geometries
- }
-
- for ( ; mFetchAddedFeaturesIt != mAddedFeatures.end(); mFetchAddedFeaturesIt++ )
- {
- int fid = mFetchAddedFeaturesIt->id();
-
- if ( mFetchConsidered.contains( fid ) )
- // must have changed geometry outside rectangle
- continue;
-
- if ( !mFetchRect.isEmpty() &&
- mFetchAddedFeaturesIt->geometry() &&
- !mFetchAddedFeaturesIt->geometry()->intersects( mFetchRect ) )
- // skip added features not in rectangle
- continue;
-
- f.setFeatureId( fid );
- f.setValid( true );
-
- if ( mFetchGeometry )
- f.setGeometry( *mFetchAddedFeaturesIt->geometry() );
-
- if ( mFetchAttributes.size() > 0 )
- {
- f.setAttributeMap( mFetchAddedFeaturesIt->attributeMap() );
- updateFeatureAttributes( f );
- }
-
- mFetchAddedFeaturesIt++;
- return true;
- }
-
- // no more added features
- }
-
- while ( dataProvider()->nextFeature( f ) )
- {
- if ( mFetchConsidered.contains( f.id() ) )
- continue;
-
- if ( mEditable )
- updateFeatureAttributes( f );
-
- // found it
- return true;
- }
-
- mFetching = false;
- return false;
+QgsFeatureIterator QgsVectorLayer::getFeatures( QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
+{
+ return QgsFeatureIterator( new QgsVectorLayerIterator( this, fetchAttributes, rect, fetchGeometry, useIntersect ) );
}
+
bool QgsVectorLayer::featureAtId( int featureId, QgsFeature& f, bool fetchGeometries, bool fetchAttributes )
{
if ( !mDataProvider )
@@ -1594,7 +1456,7 @@
mDataProvider->featureAtId( featureId, tmp, false, mDataProvider->attributeIndexes() );
f.setAttributeMap( tmp.attributeMap() );
}
- updateFeatureAttributes( f, true );
+ updateFeatureAttributes( f, pendingAllAttributesList() );
}
return true;
}
@@ -1621,7 +1483,7 @@
{
if ( mDataProvider->featureAtId( featureId, f, fetchGeometries, mDataProvider->attributeIndexes() ) )
{
- updateFeatureAttributes( f, true );
+ updateFeatureAttributes( f, pendingAllAttributesList() );
return true;
}
}
@@ -3444,6 +3306,7 @@
QgsFeatureList features;
QgsAttributeList allAttrs = mDataProvider->attributeIndexes();
+ QgsAttributeList pendingAllAttrs = pendingAllAttributesList();
for ( QgsFeatureIds::iterator it = mSelectedFeatureIds.begin(); it != mSelectedFeatureIds.end(); ++it )
{
@@ -3468,7 +3331,7 @@
mDataProvider->featureAtId( *it, feat, true, allAttrs );
}
- updateFeatureAttributes( feat );
+ updateFeatureAttributes( feat, pendingAllAttrs );
updateFeatureGeometry( feat );
features << feat;
Modified: branches/threading-branch/src/core/qgsvectorlayer.h
===================================================================
--- branches/threading-branch/src/core/qgsvectorlayer.h 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/core/qgsvectorlayer.h 2010-07-03 16:50:45 UTC (rev 13881)
@@ -30,11 +30,14 @@
#include "qgssnapper.h"
#include "qgsfield.h"
+#include "qgsvectordataprovider.h"
+
class QPainter;
class QImage;
class QgsAttributeAction;
class QgsCoordinateTransform;
+class QgsFeatureIterator;
class QgsGeometry;
class QgsGeometryVertexIndex;
class QgsMapToPixel;
@@ -50,11 +53,7 @@
class QgsFeatureRendererV2;
-typedef QList<int> QgsAttributeList;
-typedef QSet<int> QgsFeatureIds;
-typedef QSet<int> QgsAttributeIds;
-
/** \ingroup core
* Vector layer backed by a data source provider.
*/
@@ -180,9 +179,9 @@
void setUsingRendererV2( bool usingRendererV2 );
/** Draw layer with renderer V2. Added in QGIS 1.4 */
- void drawRendererV2( QgsRenderContext& rendererContext, bool labeling );
+ void drawRendererV2( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi );
/** Draw layer with renderer V2 using symbol levels. Added in QGIS 1.4 */
- void drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling );
+ void drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling, QgsFeatureIterator& fi );
/** Returns point, line or polygon */
QGis::GeometryType geometryType() const;
@@ -255,6 +254,16 @@
bool nextFeature( QgsFeature& feature );
+ /**
+ * Start iterating over features of the layer.
+ * For new code, consider using this method instead of select/nextFeature combo.
+ * @note Added in v1.6
+ */
+ QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+ QgsRectangle rect = QgsRectangle(),
+ bool fetchGeometry = true,
+ bool useIntersect = false );
+
/**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
@return true in case of success*/
bool featureAtId( int featureId, QgsFeature &f, bool fetchGeometries = true, bool fetchAttributes = true );
@@ -652,7 +661,7 @@
static int currentVertexMarkerSize();
/**Update feature with uncommited attribute updates*/
- void updateFeatureAttributes( QgsFeature &f, bool all = false );
+ void updateFeatureAttributes( QgsFeature &f, const QgsAttributeList& fetchAttributes );
/**Update feature with uncommited geometry updates*/
void updateFeatureGeometry( QgsFeature &f );
@@ -779,15 +788,9 @@
//annotation form for this layer
QString mAnnotationForm;
- bool mFetching;
- QgsRectangle mFetchRect;
- QgsAttributeList mFetchAttributes;
- QgsAttributeList mFetchProvAttributes;
- bool mFetchGeometry;
+ QgsFeatureIterator mOldApiIter;
+ friend class QgsVectorLayerIterator;
- QSet<int> mFetchConsidered;
- QgsGeometryMap::iterator mFetchChangedGeomIt;
- QgsFeatureList::iterator mFetchAddedFeaturesIt;
};
#endif
Added: branches/threading-branch/src/core/qgsvectorlayeriterator.cpp
===================================================================
--- branches/threading-branch/src/core/qgsvectorlayeriterator.cpp (rev 0)
+++ branches/threading-branch/src/core/qgsvectorlayeriterator.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,210 @@
+#include "qgsvectorlayeriterator.h"
+
+#include "qgsvectorlayer.h"
+
+#include "qgsgeometry.h"
+#include "qgslogger.h"
+
+// used from QgsVectorLayer:
+// - mDataProvider
+// - mEditable
+// - mDeletedFeatureIds
+// - mAddedFeatures
+// - mChangedGeometries
+// - mUpdatedFields
+// - mAddedAttributeIds
+// - updateFeatureAttributes()
+
+QgsVectorLayerIterator::QgsVectorLayerIterator( QgsVectorLayer* l,
+ QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
+: QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect),
+ L(l)
+{
+
+ if ( !L->mDataProvider )
+ {
+ mClosed = true;
+ return;
+ }
+
+ mFetchConsidered = L->mDeletedFeatureIds;
+
+ if ( L->mEditable )
+ {
+ mFetchAddedFeaturesIt = L->mAddedFeatures.begin();
+ mFetchChangedGeomIt = L->mChangedGeometries.begin();
+ }
+
+ //look in the normal features of the provider
+ if ( mFetchAttributes.size() > 0 )
+ {
+ if ( L->mEditable )
+ {
+ // fetch only available field from provider
+ mFetchProvAttributes.clear();
+ for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); it++ )
+ {
+ if ( !L->mUpdatedFields.contains( *it ) || L->mAddedAttributeIds.contains( *it ) )
+ continue;
+
+ mFetchProvAttributes << *it;
+ }
+
+ mProvIter = L->mDataProvider->getFeatures( mFetchProvAttributes, rect, fetchGeometry, useIntersect );
+ }
+ else
+ mProvIter = L->mDataProvider->getFeatures( mFetchAttributes, rect, fetchGeometry, useIntersect );
+ }
+ else
+ {
+ mProvIter = L->mDataProvider->getFeatures( QgsAttributeList(), rect, fetchGeometry, useIntersect );
+ }
+
+}
+
+QgsVectorLayerIterator::~QgsVectorLayerIterator()
+{
+ close();
+}
+
+
+bool QgsVectorLayerIterator::nextFeature(QgsFeature& f)
+{
+ if ( mClosed )
+ return false;
+
+ if ( L->mEditable )
+ {
+ if ( !mRect.isEmpty() )
+ {
+ // check if changed geometries are in rectangle
+ for ( ; mFetchChangedGeomIt != L->mChangedGeometries.end(); mFetchChangedGeomIt++ )
+ {
+ int fid = mFetchChangedGeomIt.key();
+
+ if ( mFetchConsidered.contains( fid ) )
+ // skip deleted features
+ continue;
+
+ mFetchConsidered << fid;
+
+ if ( !mFetchChangedGeomIt->intersects( mRect ) )
+ // skip changed geometries not in rectangle and don't check again
+ continue;
+
+ f.setFeatureId( fid );
+ f.setValid( true );
+
+ if ( mFetchGeometry )
+ f.setGeometry( mFetchChangedGeomIt.value() );
+
+ if ( mFetchAttributes.size() > 0 )
+ {
+ if ( fid < 0 )
+ {
+ // fid<0 => in mAddedFeatures
+ bool found = false;
+
+ for ( QgsFeatureList::iterator it = L->mAddedFeatures.begin(); it != L->mAddedFeatures.end(); it++ )
+ {
+ if ( fid != it->id() )
+ {
+ found = true;
+ f.setAttributeMap( it->attributeMap() );
+ break;
+ }
+ }
+
+ if ( !found )
+ QgsDebugMsg( QString( "No attributes for the added feature %1 found" ).arg( f.id() ) );
+ }
+ else
+ {
+ // retrieve attributes from provider
+ QgsFeature tmp;
+ // TODO: do not fetch here using featureAtId - do it when iterating in provider
+ L->mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
+ L->updateFeatureAttributes( tmp, mFetchAttributes );
+ f.setAttributeMap( tmp.attributeMap() );
+ }
+ }
+
+ // return complete feature
+ mFetchChangedGeomIt++;
+ return true;
+ }
+
+ // no more changed geometries
+ }
+
+ for ( ; mFetchAddedFeaturesIt != L->mAddedFeatures.end(); mFetchAddedFeaturesIt++ )
+ {
+ int fid = mFetchAddedFeaturesIt->id();
+
+ if ( mFetchConsidered.contains( fid ) )
+ // must have changed geometry outside rectangle
+ continue;
+
+ if ( !mRect.isEmpty() &&
+ mFetchAddedFeaturesIt->geometry() &&
+ !mFetchAddedFeaturesIt->geometry()->intersects( mRect ) )
+ // skip added features not in rectangle
+ continue;
+
+ f.setFeatureId( fid );
+ f.setValid( true );
+
+ if ( mFetchGeometry )
+ f.setGeometry( *mFetchAddedFeaturesIt->geometry() );
+
+ if ( mFetchAttributes.size() > 0 )
+ {
+ f.setAttributeMap( mFetchAddedFeaturesIt->attributeMap() );
+ L->updateFeatureAttributes( f, mFetchAttributes );
+ }
+
+ mFetchAddedFeaturesIt++;
+ return true;
+ }
+
+ // no more added features
+ }
+
+ while ( mProvIter.nextFeature( f ) )
+ {
+ if ( mFetchConsidered.contains( f.id() ) )
+ continue;
+
+ if ( L->mEditable )
+ L->updateFeatureAttributes( f, mFetchAttributes );
+
+ // found it
+ return true;
+ }
+
+ close();
+ return false;
+}
+
+bool QgsVectorLayerIterator::rewind()
+{
+ if (mClosed)
+ return false;
+
+ // TODO: rewind editing stuff
+ mProvIter.rewind();
+ return false;
+}
+
+bool QgsVectorLayerIterator::close()
+{
+ if (mClosed)
+ return false;
+
+ mProvIter.close();
+ mClosed = true;
+ return true;
+}
Added: branches/threading-branch/src/core/qgsvectorlayeriterator.h
===================================================================
--- branches/threading-branch/src/core/qgsvectorlayeriterator.h (rev 0)
+++ branches/threading-branch/src/core/qgsvectorlayeriterator.h 2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,41 @@
+#ifndef QGSVECTORLAYERITERATOR_H
+#define QGSVECTORLAYERITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+class QgsVectorLayer;
+
+class QgsVectorLayerIterator : public QgsVectorDataProviderIterator
+{
+public:
+
+ QgsVectorLayerIterator( QgsVectorLayer* l,
+ QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect );
+
+ ~QgsVectorLayerIterator();
+
+ //! fetch next feature, return true on success
+ virtual bool nextFeature(QgsFeature& f);
+
+ //! reset the iterator to the starting position
+ virtual bool rewind();
+
+ //! end of iterating: free the resources / lock
+ virtual bool close();
+
+protected:
+ QgsVectorLayer* L;
+
+ QgsAttributeList mFetchProvAttributes;
+ QgsFeatureIterator mProvIter;
+
+ QSet<int> mFetchConsidered;
+ QgsGeometryMap::iterator mFetchChangedGeomIt;
+ QgsFeatureList::iterator mFetchAddedFeaturesIt;
+
+};
+
+#endif // QGSVECTORLAYERITERATOR_H
Modified: branches/threading-branch/src/gui/qgsmaptip.cpp
===================================================================
--- branches/threading-branch/src/gui/qgsmaptip.cpp 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/gui/qgsmaptip.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -15,7 +15,7 @@
// QGIS includes
#include <qgsmapcanvas.h>
#include <qgsmaplayer.h>
-#include <qgsvectordataprovider.h>
+#include <qgsvectorlayer.h>
#include <qgsfield.h>
// Qt includes
Modified: branches/threading-branch/src/providers/ogr/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/providers/ogr/CMakeLists.txt 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/ogr/CMakeLists.txt 2010-07-03 16:50:45 UTC (rev 13881)
@@ -1,5 +1,5 @@
-SET (OGR_SRCS qgsogrprovider.cpp)
+SET (OGR_SRCS qgsogrprovider.cpp qgsogrfeatureiterator.cpp)
SET(OGR_MOC_HDRS qgsogrprovider.h)
Added: branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.cpp
===================================================================
--- branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.cpp (rev 0)
+++ branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,189 @@
+#include "qgsogrfeatureiterator.h"
+
+#include "qgsogrprovider.h"
+
+#include "qgsapplication.h"
+#include "qgslogger.h"
+#include "qgsgeometry.h"
+
+// P:
+// - ogrLayer
+// - mFetchFeaturesWithoutGeom
+// - getFeatureAttribute()
+
+QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrProvider* p,
+ QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
+ : QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect),
+ P(p)
+{
+ // first of all, lock the OGR layer!
+ QgsDebugMsg("trying to lock OGR layer");
+ P->mLayerMutex.lock();
+
+ // set the selection rectangle pointer to 0
+ mSelectionRectangle = 0;
+
+
+ // spatial query to select features
+ if ( rect.isEmpty() )
+ {
+ OGR_L_SetSpatialFilter( P->ogrLayer, 0 );
+ }
+ else
+ {
+ OGRGeometryH filter = 0;
+ QString wktExtent = QString( "POLYGON((%1))" ).arg( rect.asPolygon() );
+ QByteArray ba = wktExtent.toAscii();
+ const char *wktText = ba;
+
+ if ( useIntersect )
+ {
+ // store the selection rectangle for use in filtering features during
+ // an identify and display attributes
+ if ( mSelectionRectangle )
+ OGR_G_DestroyGeometry( mSelectionRectangle );
+
+ OGR_G_CreateFromWkt(( char ** )&wktText, NULL, &mSelectionRectangle );
+ wktText = ba;
+ }
+
+ OGR_G_CreateFromWkt(( char ** )&wktText, NULL, &filter );
+ QgsDebugMsg( "Setting spatial filter using " + wktExtent );
+ OGR_L_SetSpatialFilter( P->ogrLayer, filter );
+ OGR_G_DestroyGeometry( filter );
+ }
+
+ //start with first feature
+ OGR_L_ResetReading( P->ogrLayer );
+
+}
+
+QgsOgrFeatureIterator::~QgsOgrFeatureIterator()
+{
+ close();
+}
+
+
+bool QgsOgrFeatureIterator::nextFeature(QgsFeature& feature)
+{
+
+ feature.setValid( false );
+
+ OGRFeatureH fet;
+ QgsRectangle selectionRect;
+
+ while (( fet = OGR_L_GetNextFeature( P->ogrLayer ) ) != NULL )
+ {
+ // skip features without geometry
+ if ( !P->mFetchFeaturesWithoutGeom && OGR_F_GetGeometryRef( fet ) == NULL )
+ {
+ OGR_F_Destroy( fet );
+ continue;
+ }
+
+ OGRFeatureDefnH featureDefinition = OGR_F_GetDefnRef( fet );
+ QString featureTypeName = featureDefinition ? QString( OGR_FD_GetName( featureDefinition ) ) : QString( "" );
+ feature.setFeatureId( OGR_F_GetFID( fet ) );
+ feature.clearAttributeMap();
+ feature.setTypeName( featureTypeName );
+
+ /* fetch geometry */
+ if ( mFetchGeometry || mUseIntersect )
+ {
+ OGRGeometryH geom = OGR_F_GetGeometryRef( fet );
+
+ if ( geom == 0 )
+ {
+ OGR_F_Destroy( fet );
+ continue;
+ }
+
+ // get the wkb representation
+ unsigned char *wkb = new unsigned char[OGR_G_WkbSize( geom )];
+ OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
+
+ feature.setGeometryAndOwnership( wkb, OGR_G_WkbSize( geom ) );
+
+ if ( mUseIntersect )
+ {
+ //precise test for intersection with search rectangle
+ //first make QgsRectangle from OGRPolygon
+ OGREnvelope env;
+ memset( &env, 0, sizeof( env ) );
+ if ( mSelectionRectangle )
+ OGR_G_GetEnvelope( mSelectionRectangle, &env );
+ if ( env.MinX != 0 || env.MinY != 0 || env.MaxX != 0 || env.MaxY != 0 ) //if envelope is invalid, skip the precise intersection test
+ {
+ selectionRect.set( env.MinX, env.MinY, env.MaxX, env.MaxY );
+ if ( !feature.geometry()->intersects( selectionRect ) )
+ {
+ OGR_F_Destroy( fet );
+ continue;
+ }
+ }
+
+ }
+ }
+
+ /* fetch attributes */
+ for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); ++it )
+ {
+ P->getFeatureAttribute( fet, feature, *it );
+ }
+
+ /* we have a feature, end this cycle */
+ break;
+
+ } /* while */
+
+ if ( fet )
+ {
+ if ( OGR_F_GetGeometryRef( fet ) != NULL )
+ {
+ feature.setValid( true );
+ }
+ else
+ {
+ feature.setValid( false );
+ }
+ OGR_F_Destroy( fet );
+ return true;
+ }
+ else
+ {
+ QgsDebugMsg( "Feature is null" );
+ // probably should reset reading here
+ OGR_L_ResetReading( P->ogrLayer );
+ return false;
+ }
+
+}
+
+bool QgsOgrFeatureIterator::rewind()
+{
+ OGR_L_ResetReading( P->ogrLayer );
+
+ return true;
+}
+
+bool QgsOgrFeatureIterator::close()
+{
+ if (mClosed)
+ return false;
+
+ if ( mSelectionRectangle )
+ {
+ OGR_G_DestroyGeometry( mSelectionRectangle );
+ mSelectionRectangle = 0;
+ }
+
+ // we're done - unlock the mutex
+ QgsDebugMsg("unlocking OGR layer");
+ P->mLayerMutex.unlock();
+
+ mClosed = true;
+ return true;
+}
Added: branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.h
===================================================================
--- branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.h (rev 0)
+++ branches/threading-branch/src/providers/ogr/qgsogrfeatureiterator.h 2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,37 @@
+#ifndef QGSOGRFEATUREITERATOR_H
+#define QGSOGRFEATUREITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+class QgsOgrProvider;
+
+#include <ogr_api.h>
+
+class QgsOgrFeatureIterator : public QgsVectorDataProviderIterator
+{
+public:
+ QgsOgrFeatureIterator( QgsOgrProvider* p,
+ QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect );
+
+ ~QgsOgrFeatureIterator();
+
+ //! fetch next feature, return true on success
+ virtual bool nextFeature(QgsFeature& f);
+
+ //! reset the iterator to the starting position
+ virtual bool rewind();
+
+ //! end of iterating: free the resources / lock
+ virtual bool close();
+
+protected:
+ QgsOgrProvider* P;
+
+ //! Selection rectangle
+ OGRGeometryH mSelectionRectangle;
+};
+
+#endif // QGSOGRFEATUREITERATOR_H
Modified: branches/threading-branch/src/providers/ogr/qgsogrprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/ogr/qgsogrprovider.cpp 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/ogr/qgsogrprovider.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -87,8 +87,6 @@
QgsApplication::registerOgrDrivers();
- // set the selection rectangle pointer to 0
- mSelectionRectangle = 0;
// make connection to the data source
QgsDebugMsg( "Data source uri is " + uri );
@@ -213,11 +211,6 @@
extent_ = 0;
}
- if ( mSelectionRectangle )
- {
- OGR_G_DestroyGeometry( mSelectionRectangle );
- mSelectionRectangle = 0;
- }
}
bool QgsOgrProvider::setSubsetString( QString theSQL )
@@ -403,12 +396,31 @@
return ogrDriverName;
}
+#include "qgsogrfeatureiterator.h"
+QgsFeatureIterator QgsOgrProvider::getFeatures( QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
+{
+ if ( !valid )
+ {
+ QgsDebugMsg( "Read attempt on an invalid OGR layer" );
+ return QgsFeatureIterator();
+ }
+
+ return QgsFeatureIterator( new QgsOgrFeatureIterator(this, fetchAttributes, rect, fetchGeometry, useIntersect) );
+}
+
+
bool QgsOgrProvider::featureAtId( int featureId,
QgsFeature& feature,
bool fetchGeometry,
QgsAttributeList fetchAttributes )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
OGRFeatureH fet = OGR_L_GetFeature( ogrLayer, featureId );
if ( fet == NULL )
return false;
@@ -456,140 +468,27 @@
bool QgsOgrProvider::nextFeature( QgsFeature& feature )
{
- feature.setValid( false );
-
- if ( !valid )
- {
- QgsLogger::warning( "Read attempt on an invalid shapefile data source" );
- return false;
- }
-
- OGRFeatureH fet;
- QgsRectangle selectionRect;
-
- while (( fet = OGR_L_GetNextFeature( ogrLayer ) ) != NULL )
- {
- // skip features without geometry
- if ( !mFetchFeaturesWithoutGeom && OGR_F_GetGeometryRef( fet ) == NULL )
- {
- OGR_F_Destroy( fet );
- continue;
- }
-
- OGRFeatureDefnH featureDefinition = OGR_F_GetDefnRef( fet );
- QString featureTypeName = featureDefinition ? QString( OGR_FD_GetName( featureDefinition ) ) : QString( "" );
- feature.setFeatureId( OGR_F_GetFID( fet ) );
- feature.clearAttributeMap();
- feature.setTypeName( featureTypeName );
-
- /* fetch geometry */
- if ( mFetchGeom || mUseIntersect )
- {
- OGRGeometryH geom = OGR_F_GetGeometryRef( fet );
-
- if ( geom == 0 )
- {
- OGR_F_Destroy( fet );
- continue;
- }
-
- // get the wkb representation
- unsigned char *wkb = new unsigned char[OGR_G_WkbSize( geom )];
- OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
-
- feature.setGeometryAndOwnership( wkb, OGR_G_WkbSize( geom ) );
-
- if ( mUseIntersect )
- {
- //precise test for intersection with search rectangle
- //first make QgsRectangle from OGRPolygon
- OGREnvelope env;
- memset( &env, 0, sizeof( env ) );
- if ( mSelectionRectangle )
- OGR_G_GetEnvelope( mSelectionRectangle, &env );
- if ( env.MinX != 0 || env.MinY != 0 || env.MaxX != 0 || env.MaxY != 0 ) //if envelope is invalid, skip the precise intersection test
- {
- selectionRect.set( env.MinX, env.MinY, env.MaxX, env.MaxY );
- if ( !feature.geometry()->intersects( selectionRect ) )
- {
- OGR_F_Destroy( fet );
- continue;
- }
- }
-
- }
- }
-
- /* fetch attributes */
- for ( QgsAttributeList::iterator it = mAttributesToFetch.begin(); it != mAttributesToFetch.end(); ++it )
- {
- getFeatureAttribute( fet, feature, *it );
- }
-
- /* we have a feature, end this cycle */
- break;
-
- } /* while */
-
- if ( fet )
- {
- if ( OGR_F_GetGeometryRef( fet ) != NULL )
- {
- feature.setValid( true );
- }
- else
- {
- feature.setValid( false );
- }
- OGR_F_Destroy( fet );
+ if (mOldApiIter.nextFeature(feature))
return true;
- }
else
{
- QgsDebugMsg( "Feature is null" );
- // probably should reset reading here
- OGR_L_ResetReading( ogrLayer );
+ mOldApiIter.close(); // make sure to unlock the layer
return false;
}
}
+#include <QThread>
void QgsOgrProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
{
- mUseIntersect = useIntersect;
- mAttributesToFetch = fetchAttributes;
- mFetchGeom = fetchGeometry;
-
- // spatial query to select features
- if ( rect.isEmpty() )
+ if (qApp->thread() != QThread::currentThread())
{
- OGR_L_SetSpatialFilter( ogrLayer, 0 );
+ QgsDebugMsg("accessing old provider API from non-gui thread! (IGNORING)");
+ return;
}
- else
- {
- OGRGeometryH filter = 0;
- QString wktExtent = QString( "POLYGON((%1))" ).arg( rect.asPolygon() );
- QByteArray ba = wktExtent.toAscii();
- const char *wktText = ba;
- if ( useIntersect )
- {
- // store the selection rectangle for use in filtering features during
- // an identify and display attributes
- if ( mSelectionRectangle )
- OGR_G_DestroyGeometry( mSelectionRectangle );
-
- OGR_G_CreateFromWkt(( char ** )&wktText, NULL, &mSelectionRectangle );
- wktText = ba;
- }
-
- OGR_G_CreateFromWkt(( char ** )&wktText, NULL, &filter );
- QgsDebugMsg( "Setting spatial filter using " + wktExtent );
- OGR_L_SetSpatialFilter( ogrLayer, filter );
- OGR_G_DestroyGeometry( filter );
- }
-
- //start with first feature
- OGR_L_ResetReading( ogrLayer );
+ //if (mOldApiIter != QgsFeatureIterator())
+ mOldApiIter.close();
+ mOldApiIter = getFeatures( fetchAttributes, rect, fetchGeometry, useIntersect );
}
@@ -613,6 +512,9 @@
{
if ( !extent_ )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
extent_ = calloc( sizeof( OGREnvelope ), 1 );
// get the extent_ (envelope) of the layer
@@ -732,7 +634,9 @@
void QgsOgrProvider::rewind()
{
- OGR_L_ResetReading( ogrLayer );
+ // the iterator is closed everyt
+ //mOldApiIter = getFeatures( fetchAttributes, rect, fetchGeometry, useIntersect );
+ mOldApiIter.rewind();
}
@@ -746,6 +650,9 @@
bool QgsOgrProvider::addFeature( QgsFeature& f )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
bool returnValue = true;
OGRFeatureDefnH fdef = OGR_L_GetLayerDefn( ogrLayer );
OGRFeatureH feature = OGR_F_Create( fdef );
@@ -848,6 +755,9 @@
bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
bool returnvalue = true;
for ( QList<QgsField>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter )
@@ -888,6 +798,9 @@
bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
{
long fid = ( long ) it.key();
@@ -953,6 +866,9 @@
bool QgsOgrProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
OGRErr res;
OGRFeatureH theOGRFeature = 0;
OGRGeometryH theNewGeometry = 0;
@@ -1060,6 +976,9 @@
bool QgsOgrProvider::deleteFeature( int id )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
return OGR_L_DeleteFeature( ogrLayer, id ) == OGRERR_NONE;
}
@@ -1784,6 +1703,9 @@
void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
QgsField fld = mAttributeFields[index];
QString theLayerName = OGR_FD_GetName( OGR_L_GetLayerDefn( ogrLayer ) );
@@ -1820,6 +1742,9 @@
QVariant QgsOgrProvider::minimumValue( int index )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
QgsField fld = mAttributeFields[index];
QString theLayerName = OGR_FD_GetName( OGR_L_GetLayerDefn( ogrLayer ) );
@@ -1854,6 +1779,9 @@
QVariant QgsOgrProvider::maximumValue( int index )
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
QgsField fld = mAttributeFields[index];
QString theLayerName = OGR_FD_GetName( OGR_L_GetLayerDefn( ogrLayer ) );
@@ -1895,6 +1823,9 @@
bool QgsOgrProvider::syncToDisc()
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
OGR_L_SyncToDisk( ogrLayer );
//for shapefiles: is there already a spatial index?
@@ -1923,6 +1854,9 @@
void QgsOgrProvider::recalculateFeatureCount()
{
+ // make sure no other thread is accessing the layer right now
+ QMutexLocker layerLocker(&mLayerMutex);
+
OGRGeometryH filter = OGR_L_GetSpatialFilter( ogrLayer );
if ( filter )
{
Modified: branches/threading-branch/src/providers/ogr/qgsogrprovider.h
===================================================================
--- branches/threading-branch/src/providers/ogr/qgsogrprovider.h 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/ogr/qgsogrprovider.h 2010-07-03 16:50:45 UTC (rev 13881)
@@ -24,6 +24,8 @@
#include <ogr_api.h>
+#include <QMutex>
+
/**
\class QgsOgrProvider
\brief Data provider for ESRI shapefiles
@@ -79,6 +81,12 @@
*/
virtual bool nextFeature( QgsFeature& feature );
+
+ virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+ QgsRectangle rect = QgsRectangle(),
+ bool fetchGeometry = true,
+ bool useIntersect = false );
+
/**
* Gets the feature at the given feature ID.
* @param featureId id of the feature
@@ -279,13 +287,12 @@
QString ogrDriverName;
bool valid;
- //! Flag to indicate that spatial intersect should be used in selecting features
- bool mUseIntersect;
int geomType;
long featuresCounted;
- //! Selection rectangle
- OGRGeometryH mSelectionRectangle;
+ QgsFeatureIterator mOldApiIter;
+ friend class QgsOgrFeatureIterator;
+
/**Adds one feature*/
bool addFeature( QgsFeature& f );
/**Deletes one feature*/
@@ -295,4 +302,6 @@
/**Calls OGR_L_SyncToDisk and recreates the spatial index if present*/
bool syncToDisc();
+
+ QMutex mLayerMutex;
};
Modified: branches/threading-branch/src/providers/osm/osmprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/osm/osmprovider.cpp 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/osm/osmprovider.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -22,6 +22,7 @@
#include "qgslogger.h"
#include "qgsvectordataprovider.h"
#include "qgsapplication.h"
+#include "qgsvectorlayer.h"
#include <QFileInfo>
#include <QDateTime>
Modified: branches/threading-branch/src/providers/postgres/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/providers/postgres/CMakeLists.txt 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/postgres/CMakeLists.txt 2010-07-03 16:50:45 UTC (rev 13881)
@@ -2,7 +2,7 @@
########################################################
# Files
-SET(PG_SRCS qgspostgresprovider.cpp)
+SET(PG_SRCS qgspostgresprovider.cpp qgspostgresfeatureiterator.cpp)
SET(PG_MOC_HDRS qgspostgresprovider.h)
Added: branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.cpp
===================================================================
--- branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.cpp (rev 0)
+++ branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,166 @@
+#include "qgspostgresfeatureiterator.h"
+
+#include "qgspostgresprovider.h"
+
+#include "qgslogger.h"
+
+// used from provider:
+// - providerId
+// - connectionRO
+// - geometryColumn
+// - srid
+// - sqlWhereClause
+// - featuresCounted
+// - declareCursor()
+// - getFeature()
+// - quotedIdentifier()
+
+QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresProvider* p,
+ QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
+: QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect),
+ P(p)
+ , mFeatureQueueSize( 200 )
+{
+ P->mConnectionROMutex.lock();
+
+ QString cursorName = QString( "qgisf%1" ).arg( P->providerId );
+
+ QString whereClause;
+
+ if ( !rect.isEmpty() )
+ {
+ if ( useIntersect )
+ {
+ // Contributed by #qgis irc "creeping"
+ // This version actually invokes PostGIS's use of spatial indexes
+ whereClause = QString( "%1 && setsrid('BOX3D(%2)'::box3d,%3) and intersects(%1,setsrid('BOX3D(%2)'::box3d,%3))" )
+ .arg( P->quotedIdentifier( P->geometryColumn ) )
+ .arg( rect.asWktCoordinates() )
+ .arg( P->srid );
+ }
+ else
+ {
+ whereClause = QString( "%1 && setsrid('BOX3D(%2)'::box3d,%3)" )
+ .arg( P->quotedIdentifier( P->geometryColumn ) )
+ .arg( rect.asWktCoordinates() )
+ .arg( P->srid );
+ }
+ }
+
+ if ( !P->sqlWhereClause.isEmpty() )
+ {
+ if ( !whereClause.isEmpty() )
+ whereClause += " and ";
+
+ whereClause += "(" + P->sqlWhereClause + ")";
+ }
+
+ if ( !P->declareCursor( cursorName, fetchAttributes, fetchGeometry, whereClause ) )
+ {
+ mClosed = true;
+ return;
+ }
+
+ mFetched = 0;
+}
+
+QgsPostgresFeatureIterator::~QgsPostgresFeatureIterator()
+{
+ close();
+}
+
+
+bool QgsPostgresFeatureIterator::nextFeature(QgsFeature& feature)
+{
+ feature.setValid( false );
+
+ if ( mClosed )
+ return false;
+
+ QString cursorName = QString( "qgisf%1" ).arg( P->providerId );
+
+ if ( mFeatureQueue.empty() )
+ {
+ QString fetch = QString( "fetch forward %1 from %2" ).arg( mFeatureQueueSize ).arg( cursorName );
+ if ( P->connectionRO->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously
+ {
+ QgsDebugMsg( "PQsendQuery failed" );
+ }
+
+ QgsPostgresProvider::Result queryResult;
+ while (( queryResult = P->connectionRO->PQgetResult() ) )
+ {
+ int rows = PQntuples( queryResult );
+ if ( rows == 0 )
+ continue;
+
+ for ( int row = 0; row < rows; row++ )
+ {
+ mFeatureQueue.push( QgsFeature() );
+ P->getFeature( queryResult, row, mFetchGeometry, mFeatureQueue.back(), mFetchAttributes );
+ } // for each row in queue
+ }
+ }
+
+ if ( mFeatureQueue.empty() )
+ {
+ QgsDebugMsg( QString( "finished after %1 features" ).arg( mFetched ) );
+
+ close();
+
+ if ( P->featuresCounted < mFetched )
+ {
+ QgsDebugMsg( QString( "feature count adjusted from %1 to %2" ).arg( P->featuresCounted ).arg( mFetched ) );
+ P->featuresCounted = mFetched;
+ }
+ return false;
+ }
+
+ // Now return the next feature from the queue
+ if ( mFetchGeometry )
+ {
+ QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership();
+ feature.setGeometry( featureGeom );
+ }
+ else
+ {
+ feature.setGeometryAndOwnership( 0, 0 );
+ }
+ feature.setFeatureId( mFeatureQueue.front().id() );
+ feature.setAttributeMap( mFeatureQueue.front().attributeMap() );
+
+ mFeatureQueue.pop();
+ mFetched++;
+
+ feature.setValid( true );
+ return true;
+}
+
+bool QgsPostgresFeatureIterator::rewind()
+{
+ if ( mClosed )
+ return false;
+
+ //move cursor to first record
+ P->connectionRO->PQexecNR( QString( "move 0 in qgisf%1" ).arg( P->providerId ) );
+
+ mFeatureQueue.empty();
+
+ return true;
+}
+
+bool QgsPostgresFeatureIterator::close()
+{
+ if ( mClosed )
+ return false;
+
+ P->connectionRO->closeCursor( QString( "qgisf%1" ).arg( P->providerId ) );
+
+ P->mConnectionROMutex.unlock();
+
+ mClosed = true;
+ return true;
+}
Added: branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.h
===================================================================
--- branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.h (rev 0)
+++ branches/threading-branch/src/providers/postgres/qgspostgresfeatureiterator.h 2010-07-03 16:50:45 UTC (rev 13881)
@@ -0,0 +1,48 @@
+#ifndef QGSPOSTGRESFEATUREITERATOR_H
+#define QGSPOSTGRESFEATUREITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+#include <queue>
+
+class QgsPostgresProvider;
+
+class QgsPostgresFeatureIterator : public QgsVectorDataProviderIterator
+{
+public:
+ QgsPostgresFeatureIterator( QgsPostgresProvider* p,
+ QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect );
+
+ ~QgsPostgresFeatureIterator();
+
+ //! fetch next feature, return true on success
+ virtual bool nextFeature(QgsFeature& f);
+
+ //! reset the iterator to the starting position
+ virtual bool rewind();
+
+ //! end of iterating: free the resources / lock
+ virtual bool close();
+
+protected:
+ QgsPostgresProvider* P;
+
+ int mFetched; // number of retrieved features
+
+ /**
+ * Feature queue that GetNextFeature will retrieve from
+ * before the next fetch from PostgreSQL
+ */
+ std::queue<QgsFeature> mFeatureQueue;
+
+ /**
+ * Maximal size of the feature queue
+ */
+ int mFeatureQueueSize;
+
+};
+
+#endif // QGSPOSTGRESFEATUREITERATOR_H
Modified: branches/threading-branch/src/providers/postgres/qgspostgresprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/postgres/qgspostgresprovider.cpp 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/postgres/qgspostgresprovider.cpp 2010-07-03 16:50:45 UTC (rev 13881)
@@ -37,6 +37,7 @@
#include "qgsproviderextentcalcevent.h"
#include "qgspostgresprovider.h"
+#include "qgspostgresfeatureiterator.h"
#include "qgslogger.h"
@@ -56,10 +57,8 @@
QgsPostgresProvider::QgsPostgresProvider( QString const & uri )
: QgsVectorDataProvider( uri )
- , mFetching( false )
, mIsDbPrimaryKey( false )
, geomType( QGis::WKBUnknown )
- , mFeatureQueueSize( 200 )
, mUseEstimatedMetadata( false )
, mPrimaryKeyDefault( QString::null )
{
@@ -304,11 +303,7 @@
void QgsPostgresProvider::disconnectDb()
{
- if ( mFetching )
- {
- connectionRO->closeCursor( QString( "qgisf%1" ).arg( providerId ) );
- mFetching = false;
- }
+ mOldApiIter.close();
if ( connectionRO )
{
@@ -337,8 +332,8 @@
for ( i = connections.begin(); i != connections.end() && i.value() != conn; i++ )
;
- assert( i.value() == conn );
- assert( i.value()->ref > 0 );
+ Q_ASSERT( i.value() == conn );
+ Q_ASSERT( i.value()->ref > 0 );
if ( --i.value()->ref == 0 )
{
@@ -520,131 +515,37 @@
}
}
-void QgsPostgresProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
+QgsFeatureIterator QgsPostgresProvider::getFeatures( QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
{
- QString cursorName = QString( "qgisf%1" ).arg( providerId );
+ return QgsFeatureIterator( new QgsPostgresFeatureIterator(this, fetchAttributes, rect, fetchGeometry, useIntersect ) );
+}
- if ( mFetching )
- {
- connectionRO->closeCursor( cursorName );
- mFetching = false;
- while ( !mFeatureQueue.empty() )
- {
- mFeatureQueue.pop();
- }
- }
-
- QString whereClause;
-
- if ( !rect.isEmpty() )
- {
- if ( useIntersect )
- {
- // Contributed by #qgis irc "creeping"
- // This version actually invokes PostGIS's use of spatial indexes
- whereClause = QString( "%1 && setsrid('BOX3D(%2)'::box3d,%3) and intersects(%1,setsrid('BOX3D(%2)'::box3d,%3))" )
- .arg( quotedIdentifier( geometryColumn ) )
- .arg( rect.asWktCoordinates() )
- .arg( srid );
- }
- else
- {
- whereClause = QString( "%1 && setsrid('BOX3D(%2)'::box3d,%3)" )
- .arg( quotedIdentifier( geometryColumn ) )
- .arg( rect.asWktCoordinates() )
- .arg( srid );
- }
- }
-
- if ( !sqlWhereClause.isEmpty() )
- {
- if ( !whereClause.isEmpty() )
- whereClause += " and ";
-
- whereClause += "(" + sqlWhereClause + ")";
- }
-
- mFetchGeom = fetchGeometry;
- mAttributesToFetch = fetchAttributes;
- if ( !declareCursor( cursorName, fetchAttributes, fetchGeometry, whereClause ) )
- return;
-
- mFetching = true;
- mFetched = 0;
+void QgsPostgresProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
+{
+ if (!mOldApiIter.isClosed())
+ mOldApiIter.close();
+ mOldApiIter = getFeatures(fetchAttributes, rect, fetchGeometry, useIntersect);
}
bool QgsPostgresProvider::nextFeature( QgsFeature& feature )
{
- feature.setValid( false );
if ( !valid )
{
QgsDebugMsg( "Read attempt on an invalid postgresql data source" );
return false;
}
- if ( !mFetching )
+ if ( mOldApiIter.isClosed() )
{
QgsDebugMsg( "nextFeature() without select()" );
return false;
}
- QString cursorName = QString( "qgisf%1" ).arg( providerId );
-
- if ( mFeatureQueue.empty() )
- {
- QString fetch = QString( "fetch forward %1 from %2" ).arg( mFeatureQueueSize ).arg( cursorName );
- if ( connectionRO->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously
- {
- QgsDebugMsg( "PQsendQuery failed" );
- }
-
- Result queryResult;
- while (( queryResult = connectionRO->PQgetResult() ) )
- {
- int rows = PQntuples( queryResult );
- if ( rows == 0 )
- continue;
-
- for ( int row = 0; row < rows; row++ )
- {
- mFeatureQueue.push( QgsFeature() );
- getFeature( queryResult, row, mFetchGeom, mFeatureQueue.back(), mAttributesToFetch );
- } // for each row in queue
- }
- }
-
- if ( mFeatureQueue.empty() )
- {
- QgsDebugMsg( QString( "finished after %1 features" ).arg( mFetched ) );
- connectionRO->closeCursor( cursorName );
- mFetching = false;
- if ( featuresCounted < mFetched )
- {
- QgsDebugMsg( QString( "feature count adjusted from %1 to %2" ).arg( featuresCounted ).arg( mFetched ) );
- featuresCounted = mFetched;
- }
- return false;
- }
-
- // Now return the next feature from the queue
- if ( mFetchGeom )
- {
- QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership();
- feature.setGeometry( featureGeom );
- }
- else
- {
- feature.setGeometryAndOwnership( 0, 0 );
- }
- feature.setFeatureId( mFeatureQueue.front().id() );
- feature.setAttributeMap( mFeatureQueue.front().attributeMap() );
-
- mFeatureQueue.pop();
- mFetched++;
-
- feature.setValid( true );
- return true;
+ return mOldApiIter.nextFeature( feature );
}
QString QgsPostgresProvider::whereClause( int featureId ) const
@@ -673,6 +574,8 @@
bool QgsPostgresProvider::featureAtId( int featureId, QgsFeature& feature, bool fetchGeometry, QgsAttributeList fetchAttributes )
{
+ QMutexLocker connectionROLocker(&mConnectionROMutex);
+
feature.setValid( false );
QString cursorName = QString( "qgisfid%1" ).arg( providerId );
@@ -758,13 +661,7 @@
void QgsPostgresProvider::rewind()
{
- if ( mFetching )
- {
- //move cursor to first record
- connectionRO->PQexecNR( QString( "move 0 in qgisf%1" ).arg( providerId ) );
- }
- mFeatureQueue.empty();
- loadFields();
+ mOldApiIter.rewind();
}
/** @todo XXX Perhaps this should be promoted to QgsDataProvider? */
@@ -1586,6 +1483,8 @@
bool QgsPostgresProvider::uniqueData( QString query, QString colName )
{
+ QMutexLocker connectionROLocker(&mConnectionROMutex);
+
// Check to see if the given column contains unique data
bool isUnique = false;
@@ -1855,6 +1754,8 @@
// Returns the minimum value of an attribute
QVariant QgsPostgresProvider::minimumValue( int index )
{
+ QMutexLocker connectionROLocker(&mConnectionROMutex);
+
try
{
// get the field name
@@ -1880,6 +1781,8 @@
// Returns the list of unique values of an attribute
void QgsPostgresProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit )
{
+ QMutexLocker connectionROLocker(&mConnectionROMutex);
+
uniqueValues.clear();
try
@@ -1917,6 +1820,8 @@
void QgsPostgresProvider::enumValues( int index, QStringList& enumList )
{
+ QMutexLocker connectionROLocker(&mConnectionROMutex);
+
enumList.clear();
QString typeName;
@@ -2048,6 +1953,8 @@
// Returns the maximum value of an attribute
QVariant QgsPostgresProvider::maximumValue( int index )
{
+ QMutexLocker connectionROLocker(&mConnectionROMutex);
+
try
{
// get the field name
@@ -2108,6 +2015,8 @@
QVariant QgsPostgresProvider::defaultValue( int fieldId )
{
+ QMutexLocker connectionROLocker(&mConnectionROMutex);
+
try
{
return defaultValue( field( fieldId ).name() );
@@ -2748,6 +2657,8 @@
if ( featuresCounted >= 0 )
return featuresCounted;
+ QMutexLocker connectionROLocker(&mConnectionROMutex);
+
// get total number of features
QString sql;
@@ -2781,6 +2692,8 @@
{
if ( layerExtent.isEmpty() )
{
+ QMutexLocker connectionROLocker(&mConnectionROMutex);
+
QString sql;
Result result;
QString ext;
Modified: branches/threading-branch/src/providers/postgres/qgspostgresprovider.h
===================================================================
--- branches/threading-branch/src/providers/postgres/qgspostgresprovider.h 2010-07-02 20:55:44 UTC (rev 13880)
+++ branches/threading-branch/src/providers/postgres/qgspostgresprovider.h 2010-07-03 16:50:45 UTC (rev 13881)
@@ -26,9 +26,10 @@
#include "qgsvectordataprovider.h"
#include "qgsrectangle.h"
#include <list>
-#include <queue>
#include <fstream>
#include <set>
+#include <vector>
+#include <QMutex>
class QgsFeature;
class QgsField;
@@ -91,6 +92,11 @@
*/
virtual bool nextFeature( QgsFeature& feature );
+ virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+ QgsRectangle rect = QgsRectangle(),
+ bool fetchGeometry = true,
+ bool useIntersect = false );
+
/**
* Gets the feature at the given feature ID.
* @param featureId id of the feature
@@ -363,12 +369,13 @@
*/
bool parseDomainCheckConstraint( QStringList& enumValues, const QString& attributeName ) const;
- bool mFetching; // true if a cursor was declared
- int mFetched; // number of retrieved features
std::vector < QgsFeature > features;
QgsFieldMap attributeFields;
QString mDataComment;
+ QgsFeatureIterator mOldApiIter;
+ friend class QgsPostgresFeatureIterator;
+
//! Data source URI struct for this layer
QgsDataSourceURI mUri;
@@ -440,17 +447,6 @@
mutable long featuresCounted;
/**
- * Feature queue that GetNextFeature will retrieve from
- * before the next fetch from PostgreSQL
- */
- std::queue<QgsFeature> mFeatureQueue;
-
- /**
- * Maximal size of the feature queue
- */
- int mFeatureQueueSize;
-
- /**
* Flag indicating whether data from binary cursors must undergo an
* endian conversion prior to use
@note
@@ -706,6 +702,8 @@
* Default value for primary key
*/
QString mPrimaryKeyDefault;
-};
+ mutable QMutex mConnectionROMutex;
+ };
+
#endif
More information about the QGIS-commit
mailing list