Skip to content

Commit

Permalink
Introduction of concept of feature sources for vector data.
Browse files Browse the repository at this point in the history
Feature sources of providers/layers should act as immutable
snapshots of the state of provider or layer, not being affected
by any concurrent changes to provider or layer while the source is in use.

Currently working just with OGR, Postgres, SpatiaLite providers.
  • Loading branch information
wonder-sk committed Dec 3, 2013
1 parent 5590ab4 commit 9d00185
Show file tree
Hide file tree
Showing 31 changed files with 846 additions and 410 deletions.
28 changes: 28 additions & 0 deletions src/core/qgsfeatureiterator.h
Expand Up @@ -58,6 +58,34 @@ class CORE_EXPORT QgsAbstractFeatureIterator
};



/** helper template that cares of two things: 1. automatic deletion of source if owned by iterator, 2. notification of open/closed iterator */
template<typename T>
class QgsAbstractFeatureIteratorFromSource : public QgsAbstractFeatureIterator
{
public:
QgsAbstractFeatureIteratorFromSource( T* source, bool ownSource, const QgsFeatureRequest& request )
: QgsAbstractFeatureIterator( request ), mSource( source ), mOwnSource( ownSource )
{
mSource->iteratorOpened( this );
}

~QgsAbstractFeatureIteratorFromSource()
{
if ( mOwnSource )
delete mSource;
}

protected:
//! to be called by from subclass in close()
void iteratorClosed() { mSource->iteratorClosed( this ); }

T* mSource;
bool mOwnSource;
};



/**
* \ingroup core
* Wrapper for iterator of features from vector data provider or vector layer
Expand Down
25 changes: 25 additions & 0 deletions src/core/qgsfeaturerequest.cpp
Expand Up @@ -168,3 +168,28 @@ bool QgsFeatureRequest::acceptFeature( const QgsFeature& feature )

return true;
}

#include "qgsfeatureiterator.h"
#include "qgslogger.h"

QgsAbstractFeatureSource::~QgsAbstractFeatureSource()
{
while ( !mActiveIterators.empty() )
{
QgsAbstractFeatureIterator *it = *mActiveIterators.begin();
QgsDebugMsg( "closing active iterator" );
it->close();
}
}

void QgsAbstractFeatureSource::iteratorOpened( QgsAbstractFeatureIterator* it )
{
mActiveIterators.insert( it );
}

void QgsAbstractFeatureSource::iteratorClosed( QgsAbstractFeatureIterator* it )
{
mActiveIterators.remove( it );
}


20 changes: 20 additions & 0 deletions src/core/qgsfeaturerequest.h
Expand Up @@ -146,4 +146,24 @@ class CORE_EXPORT QgsFeatureRequest
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsFeatureRequest::Flags )


class QgsFeatureIterator;
class QgsAbstractFeatureIterator;

/** base class that can be used for any class that is capable of returning features */
class QgsAbstractFeatureSource
{
public:
virtual ~QgsAbstractFeatureSource();

virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request ) = 0;

protected:
void iteratorOpened( QgsAbstractFeatureIterator* it );
void iteratorClosed( QgsAbstractFeatureIterator* it );

QSet< QgsAbstractFeatureIterator* > mActiveIterators;

template<typename> friend class QgsAbstractFeatureIteratorFromSource;
};

#endif // QGSFEATUREREQUEST_H
8 changes: 8 additions & 0 deletions src/core/qgsfield.cpp
Expand Up @@ -180,3 +180,11 @@ int QgsFields::fieldNameIndex( const QString& fieldName ) const
}
return -1;
}

QgsAttributeList QgsFields::allAttributesList() const
{
QgsAttributeList lst;
for ( int i = 0; i < mFields.count(); ++i )
lst.append( i );
return lst;
}
6 changes: 6 additions & 0 deletions src/core/qgsfield.h
Expand Up @@ -20,6 +20,8 @@
#include <QVariant>
#include <QVector>

typedef QList<int> QgsAttributeList;

/** \ingroup core
* Encapsulate a field in an attribute table or data source.
* QgsField stores metadata about an attribute field, including name, type
Expand Down Expand Up @@ -221,6 +223,10 @@ class CORE_EXPORT QgsFields
//! @note added in 2.1
int fieldNameIndex( const QString& fieldName ) const;

//! Utility function to get list of attribute indexes
//! @note added in 2.1
QgsAttributeList allAttributesList() const;

//! Utility function to return a list of QgsField instances
QList<QgsField> toList() const;

Expand Down
3 changes: 2 additions & 1 deletion src/core/qgsmaprendererjob.cpp
Expand Up @@ -183,7 +183,8 @@ void QgsMapRendererCustomPainterJob::start()

QPaintDevice* thePaintDevice = mPainter->device();

Q_ASSERT_X( thePaintDevice->logicalDpiX() == mSettings.outputDpi(), "Job::startRender()", "pre-set DPI not equal to painter's DPI" );
QString errMsg = QString("pre-set DPI not equal to painter's DPI (%1 vs %2)").arg(thePaintDevice->logicalDpiX()).arg(mSettings.outputDpi());
Q_ASSERT_X( thePaintDevice->logicalDpiX() == mSettings.outputDpi(), "Job::startRender()", errMsg.toAscii().data() );

delete mLabelingEngine;
mLabelingEngine = 0;
Expand Down
1 change: 1 addition & 0 deletions src/core/qgsmapsettings.cpp
Expand Up @@ -131,6 +131,7 @@ void QgsMapSettings::updateDerived()
QgsDebugMsg( QString( "Recalced pixmap dimensions (x,y) : %1, %2" ).arg( qgsDoubleToString( mVisibleExtent.width() / mMapUnitsPerPixel ) ).arg( qgsDoubleToString( mVisibleExtent.height() / mMapUnitsPerPixel ) ) );
QgsDebugMsg( QString( "Scale (assuming meters as map units) = 1:%1" ).arg( qgsDoubleToString( mScale ) ) );

mValid = true;
}


Expand Down
8 changes: 1 addition & 7 deletions src/core/qgsvectordataprovider.cpp
Expand Up @@ -228,13 +228,7 @@ QMap<QString, int> QgsVectorDataProvider::fieldNameMap() const

QgsAttributeList QgsVectorDataProvider::attributeIndexes()
{
int count = fields().count();
QgsAttributeList list;

for ( int i = 0; i < count; i++ )
list.append( i );

return list;
return fields().allAttributesList();
}

const QList< QgsVectorDataProvider::NativeType > &QgsVectorDataProvider::nativeTypes() const
Expand Down
22 changes: 20 additions & 2 deletions src/core/qgsvectordataprovider.h
Expand Up @@ -103,6 +103,24 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
*/
virtual ~QgsVectorDataProvider();

/**
* Return feature source object that can be used for querying provider's data. The returned feature source
* is independent from provider - any changes to provider's state (e.g. change of subset string) will not be
* reflected in the feature source, therefore it can be safely used for processing in background without
* having to care about possible changes within provider that may happen concurrently. Also, even in the case
* of provider being deleted, any feature source obtained from the provider will be kept alive and working
* (they are independent and owned by the caller).
*
* Sometimes there are cases when some data needs to be shared between vector data provider and its feature source.
* In such cases, the implementation must ensure that the data is not susceptible to run condition. For example,
* if it is possible that both feature source and provider may need reading/writing to some shared data at the
* same time, some synchronization mechanisms must be used (e.g. mutexes) to prevent data corruption.
*
* @note added in 2.1
* @return new instance of QgsAbstractFeatureSource (caller is responsible for deleting it)
*/
virtual QgsAbstractFeatureSource* featureSource() const { Q_ASSERT(0 && "All providers must support featureSource()"); return 0; }

/**
* Returns the permanent storage type for this layer as a friendly name.
*/
Expand Down Expand Up @@ -342,9 +360,9 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
*/
virtual bool isSaveAndLoadStyleToDBSupported() { return false; }

protected:
QVariant convertValue( QVariant::Type type, QString value );
static QVariant convertValue( QVariant::Type type, QString value );

protected:
void clearMinMaxCache();
void fillMinMaxCache();

Expand Down
7 changes: 2 additions & 5 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -906,7 +906,7 @@ QgsFeatureIterator QgsVectorLayer::getFeatures( const QgsFeatureRequest& request
if ( !mDataProvider )
return QgsFeatureIterator();

return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, request ) );
return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
}


Expand Down Expand Up @@ -2270,10 +2270,7 @@ const QgsFields &QgsVectorLayer::pendingFields() const

QgsAttributeList QgsVectorLayer::pendingAllAttributesList()
{
QgsAttributeList lst;
for ( int i = 0; i < mUpdatedFields.count(); ++i )
lst.append( i );
return lst;
return mUpdatedFields.allAttributesList();
}

QgsAttributeList QgsVectorLayer::pendingPkAttributesList()
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsvectorlayer.h
Expand Up @@ -1668,7 +1668,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
// Feature counts for each renderer symbol
QMap<QgsSymbolV2*, long> mSymbolFeatureCountMap;

friend class QgsVectorLayerFeatureIterator;
friend class QgsVectorLayerFeatureSource;
};

#endif

0 comments on commit 9d00185

Please sign in to comment.