Allow access to feature attributes by name

This commit is contained in:
Martin Dobias 2012-05-13 00:53:50 +02:00
parent 70ff8ef6dd
commit b863ca195e
14 changed files with 189 additions and 1 deletions

View File

@ -39,11 +39,34 @@ class QgsFeature
} }
%End %End
SIP_PYOBJECT __getitem__(const QString& name);
%MethodCode
int fieldIdx = sipCpp->fieldNameIndex(*a0);
if (fieldIdx == -1)
PyErr_SetString(PyExc_KeyError, a0->toAscii());
else
{
QVariant* v = new QVariant( sipCpp->attributeMap().value(fieldIdx) );
sipRes = sipConvertFromInstance(v, sipClass_QVariant, Py_None);
}
%End
void __setitem__(int key, QVariant value); void __setitem__(int key, QVariant value);
%MethodCode %MethodCode
sipCpp->addAttribute(a0, *a1); sipCpp->addAttribute(a0, *a1);
%End %End
void __setitem__(const QString& key, QVariant value);
%MethodCode
int fieldIdx = sipCpp->fieldNameIndex(*a0);
if (fieldIdx == -1)
PyErr_SetString(PyExc_KeyError, a0->toAscii());
else
{
sipCpp->addAttribute(fieldIdx, *a1);
}
%End
void __delitem__(int key); void __delitem__(int key);
%MethodCode %MethodCode
if (sipCpp->attributeMap().contains(a0)) if (sipCpp->attributeMap().contains(a0))
@ -52,6 +75,15 @@ class QgsFeature
PyErr_SetString(PyExc_KeyError, QByteArray::number(a0)); PyErr_SetString(PyExc_KeyError, QByteArray::number(a0));
%End %End
void __delitem__(const QString& name);
%MethodCode
int fieldIdx = sipCpp->fieldNameIndex(*a0);
if (fieldIdx == -1)
PyErr_SetString(PyExc_KeyError, a0->toAscii());
else
sipCpp->deleteAttribute(fieldIdx);
%End
//! Constructor //! Constructor
QgsFeature( qint64 id = 0, QString typeName = "" ); QgsFeature( qint64 id = 0, QString typeName = "" );
@ -162,5 +194,46 @@ class QgsFeature
*/ */
void setGeometryAndOwnership( unsigned char * geom /Transfer/, size_t length ); void setGeometryAndOwnership( unsigned char * geom /Transfer/, size_t length );
/** Assign a field map with the feature to allow attribute access by attribute name
* @note added in 2.0
*/
void setFieldMap( const QgsFieldMap* fields );
/** Get associated field map. may be NULL
* @note added in 2.0
*/
const QgsFieldMap* fieldMap() const;
/** Insert a value into attribute. Returns false if attribute name could not be converted to index.
* Field map must be associated to make this work.
* @note added in 2.0
*/
bool addAttribute( const QString& name, QVariant value );
/** Change a value of an attribute. Returns false if attribute name could not be converted to index.
* Field map must be associated to make this work.
* @note added in 2.0
*/
bool changeAttribute( const QString& name, QVariant value );
/** Remove an attribute value. Returns false if attribute name could not be converted to index.
* Field map must be associated to make this work.
* @note added in 2.0
*/
bool deleteAttribute( const QString& name );
/** Lookup attribute value from attribute name. Returns invalid variant if attribute name could not be converted to index.
* Field map must be associated to make this work.
* @note added in 2.0
*/
QVariant attribute( const QString& name ) const;
/** Utility method to get attribute index from name. Returns -1 if field does not exist or field map is not associated.
* Field map must be associated to make this work.
* @note added in 2.0
*/
int fieldNameIndex( const QString& fieldName ) const;
}; // class QgsFeature }; // class QgsFeature

View File

@ -14,6 +14,7 @@ email : sherman at mrcc.com
***************************************************************************/ ***************************************************************************/
#include "qgsfeature.h" #include "qgsfeature.h"
#include "qgsfield.h"
#include "qgsgeometry.h" #include "qgsgeometry.h"
#include "qgsrectangle.h" #include "qgsrectangle.h"
@ -28,6 +29,7 @@ QgsFeature::QgsFeature( QgsFeatureId id, QString typeName )
, mValid( false ) , mValid( false )
, mDirty( 0 ) , mDirty( 0 )
, mTypeName( typeName ) , mTypeName( typeName )
, mFields( 0 )
{ {
// NOOP // NOOP
} }
@ -40,6 +42,7 @@ QgsFeature::QgsFeature( QgsFeature const & rhs )
, mValid( rhs.mValid ) , mValid( rhs.mValid )
, mDirty( rhs.mDirty ) , mDirty( rhs.mDirty )
, mTypeName( rhs.mTypeName ) , mTypeName( rhs.mTypeName )
, mFields( rhs.mFields )
{ {
// copy embedded geometry // copy embedded geometry
@ -60,6 +63,7 @@ QgsFeature & QgsFeature::operator=( QgsFeature const & rhs )
mAttributes = rhs.mAttributes; mAttributes = rhs.mAttributes;
mValid = rhs.mValid; mValid = rhs.mValid;
mTypeName = rhs.mTypeName; mTypeName = rhs.mTypeName;
mFields = rhs.mFields;
// make sure to delete the old geometry (if exists) // make sure to delete the old geometry (if exists)
if ( mGeometry && mOwnsGeometry ) if ( mGeometry && mOwnsGeometry )
@ -218,3 +222,53 @@ void QgsFeature::clean()
{ {
mDirty = false; mDirty = false;
} }
bool QgsFeature::addAttribute( const QString& name, QVariant value )
{
int fieldIdx = fieldNameIndex( name );
if ( fieldIdx == -1 )
return false;
mAttributes.insert( fieldIdx, value );
return true;
}
bool QgsFeature::changeAttribute( const QString& name, QVariant value )
{
return addAttribute( name, value );
}
bool QgsFeature::deleteAttribute( const QString& name )
{
int fieldIdx = fieldNameIndex( name );
if ( fieldIdx == -1 )
return false;
mAttributes.remove( fieldIdx );
return true;
}
QVariant QgsFeature::attribute( const QString& name ) const
{
int fieldIdx = fieldNameIndex( name );
if ( fieldIdx == -1 )
return QVariant();
return mAttributes.value( fieldIdx );
}
int QgsFeature::fieldNameIndex( const QString& fieldName ) const
{
if ( !mFields )
return -1;
for ( QgsFieldMap::const_iterator it = mFields->constBegin(); it != mFields->constEnd(); ++it )
{
if ( QString::compare( it->name(), fieldName, Qt::CaseInsensitive ) == 0 )
{
return it.key();
}
}
return -1;
}

View File

@ -94,6 +94,8 @@ typedef int QgsFeatureId;
// key = field index, value = field value // key = field index, value = field value
typedef QMap<int, QVariant> QgsAttributeMap; typedef QMap<int, QVariant> QgsAttributeMap;
class QgsField;
typedef QMap<int, QgsField> QgsFieldMap;
/** \ingroup core /** \ingroup core
* The feature class encapsulates a single feature including its id, * The feature class encapsulates a single feature including its id,
@ -216,6 +218,46 @@ class CORE_EXPORT QgsFeature
*/ */
void setGeometryAndOwnership( unsigned char * geom, size_t length ); void setGeometryAndOwnership( unsigned char * geom, size_t length );
/** Assign a field map with the feature to allow attribute access by attribute name
* @note added in 2.0
*/
void setFieldMap( const QgsFieldMap* fields ) { mFields = fields; }
/** Get associated field map. may be NULL
* @note added in 2.0
*/
const QgsFieldMap* fieldMap() const { return mFields; }
/** Insert a value into attribute. Returns false if attribute name could not be converted to index.
* Field map must be associated to make this work.
* @note added in 2.0
*/
bool addAttribute( const QString& name, QVariant value );
/** Change a value of an attribute. Returns false if attribute name could not be converted to index.
* Field map must be associated to make this work.
* @note added in 2.0
*/
bool changeAttribute( const QString& name, QVariant value );
/** Remove an attribute value. Returns false if attribute name could not be converted to index.
* Field map must be associated to make this work.
* @note added in 2.0
*/
bool deleteAttribute( const QString& name );
/** Lookup attribute value from attribute name. Returns invalid variant if attribute name could not be converted to index.
* Field map must be associated to make this work.
* @note added in 2.0
*/
QVariant attribute( const QString& name ) const;
/** Utility method to get attribute index from name. Returns -1 if field does not exist or field map is not associated.
* Field map must be associated to make this work.
* @note added in 2.0
*/
int fieldNameIndex( const QString& fieldName ) const;
private: private:
//! feature id //! feature id
@ -246,6 +288,8 @@ class CORE_EXPORT QgsFeature
/// feature type name /// feature type name
QString mTypeName; QString mTypeName;
//! Optional field map for name-based attribute lookups
const QgsFieldMap* mFields;
}; // class QgsFeature }; // class QgsFeature

View File

@ -545,7 +545,7 @@ bool QgsDelimitedTextProvider::nextFeature( QgsFeature& feature )
// At this point the current feature values are valid // At this point the current feature values are valid
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
feature.setFeatureId( mFid ); feature.setFeatureId( mFid );
if ( geom ) if ( geom )

View File

@ -157,6 +157,7 @@ bool QgsGPXProvider::nextFeature( QgsFeature& feature )
feature.setGeometryAndOwnership(( unsigned char * )geo, sizeof( wkbPoint ) ); feature.setGeometryAndOwnership(( unsigned char * )geo, sizeof( wkbPoint ) );
} }
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
// add attributes if they are wanted // add attributes if they are wanted
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter ) for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
@ -248,6 +249,7 @@ bool QgsGPXProvider::nextFeature( QgsFeature& feature )
feature.setFeatureId( rte->id ); feature.setFeatureId( rte->id );
result = true; result = true;
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
// add attributes if they are wanted // add attributes if they are wanted
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter ) for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
@ -364,6 +366,7 @@ bool QgsGPXProvider::nextFeature( QgsFeature& feature )
result = true; result = true;
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
// add attributes if they are wanted // add attributes if they are wanted
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter ) for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )

View File

@ -343,6 +343,7 @@ bool QgsGrassProvider::nextFeature( QgsFeature& feature )
feature.setFeatureId( id ); feature.setFeatureId( id );
feature.clearAttributeMap(); feature.clearAttributeMap();
feature.setFieldMap( &fields() ); // allow name-based attribute lookups
// TODO int may be 64 bits (memcpy) // TODO int may be 64 bits (memcpy)
if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) ) /* points or lines */ if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) ) /* points or lines */

View File

@ -287,6 +287,7 @@ bool QgsMemoryProvider::nextFeature( QgsFeature& feature )
feature = mSelectIterator.value(); feature = mSelectIterator.value();
mSelectIterator++; mSelectIterator++;
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
} }
return hasFeature; return hasFeature;
@ -308,6 +309,7 @@ bool QgsMemoryProvider::featureAtId( QgsFeatureId featureId,
feature = *it; feature = *it;
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
return true; return true;
} }

View File

@ -537,6 +537,7 @@ bool QgsMssqlProvider::nextFeature( QgsFeature& feature )
} }
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
return true; return true;
} }
return false; return false;

View File

@ -639,6 +639,7 @@ bool QgsOgrProvider::featureAtId( QgsFeatureId featureId,
if ( !fet ) if ( !fet )
return false; return false;
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
feature.setFeatureId( OGR_F_GetFID( fet ) ); feature.setFeatureId( OGR_F_GetFID( fet ) );
feature.clearAttributeMap(); feature.clearAttributeMap();
// skip features without geometry // skip features without geometry
@ -714,6 +715,7 @@ bool QgsOgrProvider::nextFeature( QgsFeature& feature )
feature.setFeatureId( OGR_F_GetFID( fet ) ); feature.setFeatureId( OGR_F_GetFID( fet ) );
feature.clearAttributeMap(); feature.clearAttributeMap();
feature.setTypeName( featureTypeName ); feature.setTypeName( featureTypeName );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
/* fetch geometry */ /* fetch geometry */
if ( mFetchGeom || mUseIntersect ) if ( mFetchGeom || mUseIntersect )

View File

@ -651,6 +651,7 @@ bool QgsOSMDataProvider::fetchNode( QgsFeature& feature, sqlite3_stmt* stmt, boo
feature.setFeatureId( selId ); feature.setFeatureId( selId );
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
return true; return true;
} }
@ -762,6 +763,7 @@ bool QgsOSMDataProvider::fetchWay( QgsFeature& feature, sqlite3_stmt* stmt, bool
} }
feature.setFeatureId( selId ); feature.setFeatureId( selId );
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
return true; return true;
} }

View File

@ -672,6 +672,7 @@ bool QgsPostgresProvider::nextFeature( QgsFeature& feature )
mFetched++; mFetched++;
feature.setValid( true ); feature.setValid( true );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
return true; return true;
} }
@ -877,6 +878,7 @@ bool QgsPostgresProvider::featureAtId( QgsFeatureId featureId, QgsFeature& featu
mConnectionRO->closeCursor( cursorName ); mConnectionRO->closeCursor( cursorName );
feature.setValid( gotit ); feature.setValid( gotit );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
#if 0 #if 0
if ( gotit ) if ( gotit )

View File

@ -705,6 +705,7 @@ bool QgsSpatiaLiteProvider::featureAtId( QgsFeatureId featureId, QgsFeature & fe
sqlite3_finalize( stmt ); sqlite3_finalize( stmt );
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
feature.setValid( true ); feature.setValid( true );
return true; return true;
} }
@ -731,6 +732,7 @@ bool QgsSpatiaLiteProvider::nextFeature( QgsFeature & feature )
return false; return false;
} }
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
feature.setValid( true ); feature.setValid( true );
return true; return true;
} }

View File

@ -315,6 +315,7 @@ QgsSqlAnywhereProvider::nextFeature( QgsFeature & feature, SqlAnyStatement *stmt
if ( ok ) if ( ok )
{ {
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
// iterate mAttributesToFetch // iterate mAttributesToFetch
feature.clearAttributeMap(); feature.clearAttributeMap();
for ( QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin() for ( QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin()

View File

@ -172,6 +172,7 @@ void QgsWFSProvider::copyFeature( QgsFeature* f, QgsFeature& feature, bool fetch
//id and valid //id and valid
feature.setValid( true ); feature.setValid( true );
feature.setFeatureId( f->id() ); feature.setFeatureId( f->id() );
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
} }
bool QgsWFSProvider::featureAtId( QgsFeatureId featureId, bool QgsWFSProvider::featureAtId( QgsFeatureId featureId,