Skip to content

Commit

Permalink
Allow access to feature attributes by name
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Oct 8, 2012
1 parent 70ff8ef commit b863ca1
Show file tree
Hide file tree
Showing 14 changed files with 189 additions and 1 deletion.
73 changes: 73 additions & 0 deletions python/core/qgsfeature.sip
Expand Up @@ -39,11 +39,34 @@ class QgsFeature
}
%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);
%MethodCode
sipCpp->addAttribute(a0, *a1);
%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);
%MethodCode
if (sipCpp->attributeMap().contains(a0))
Expand All @@ -52,6 +75,15 @@ class QgsFeature
PyErr_SetString(PyExc_KeyError, QByteArray::number(a0));
%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
QgsFeature( qint64 id = 0, QString typeName = "" );

Expand Down Expand Up @@ -162,5 +194,46 @@ class QgsFeature
*/
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

54 changes: 54 additions & 0 deletions src/core/qgsfeature.cpp
Expand Up @@ -14,6 +14,7 @@ email : sherman at mrcc.com
***************************************************************************/

#include "qgsfeature.h"
#include "qgsfield.h"
#include "qgsgeometry.h"
#include "qgsrectangle.h"

Expand All @@ -28,6 +29,7 @@ QgsFeature::QgsFeature( QgsFeatureId id, QString typeName )
, mValid( false )
, mDirty( 0 )
, mTypeName( typeName )
, mFields( 0 )
{
// NOOP
}
Expand All @@ -40,6 +42,7 @@ QgsFeature::QgsFeature( QgsFeature const & rhs )
, mValid( rhs.mValid )
, mDirty( rhs.mDirty )
, mTypeName( rhs.mTypeName )
, mFields( rhs.mFields )
{

// copy embedded geometry
Expand All @@ -60,6 +63,7 @@ QgsFeature & QgsFeature::operator=( QgsFeature const & rhs )
mAttributes = rhs.mAttributes;
mValid = rhs.mValid;
mTypeName = rhs.mTypeName;
mFields = rhs.mFields;

// make sure to delete the old geometry (if exists)
if ( mGeometry && mOwnsGeometry )
Expand Down Expand Up @@ -218,3 +222,53 @@ void QgsFeature::clean()
{
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;
}
44 changes: 44 additions & 0 deletions src/core/qgsfeature.h
Expand Up @@ -94,6 +94,8 @@ typedef int QgsFeatureId;
// key = field index, value = field value
typedef QMap<int, QVariant> QgsAttributeMap;

class QgsField;
typedef QMap<int, QgsField> QgsFieldMap;

/** \ingroup core
* The feature class encapsulates a single feature including its id,
Expand Down Expand Up @@ -216,6 +218,46 @@ class CORE_EXPORT QgsFeature
*/
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:

//! feature id
Expand Down Expand Up @@ -246,6 +288,8 @@ class CORE_EXPORT QgsFeature
/// feature type name
QString mTypeName;

//! Optional field map for name-based attribute lookups
const QgsFieldMap* mFields;

}; // class QgsFeature

Expand Down
2 changes: 1 addition & 1 deletion src/providers/delimitedtext/qgsdelimitedtextprovider.cpp
Expand Up @@ -545,7 +545,7 @@ bool QgsDelimitedTextProvider::nextFeature( QgsFeature& feature )
// At this point the current feature values are valid

feature.setValid( true );

feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
feature.setFeatureId( mFid );

if ( geom )
Expand Down
3 changes: 3 additions & 0 deletions src/providers/gpx/qgsgpxprovider.cpp
Expand Up @@ -157,6 +157,7 @@ bool QgsGPXProvider::nextFeature( QgsFeature& feature )
feature.setGeometryAndOwnership(( unsigned char * )geo, sizeof( wkbPoint ) );
}
feature.setValid( true );
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups

// add attributes if they are wanted
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
Expand Down Expand Up @@ -248,6 +249,7 @@ bool QgsGPXProvider::nextFeature( QgsFeature& feature )
feature.setFeatureId( rte->id );
result = true;
feature.setValid( true );
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups

// add attributes if they are wanted
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
Expand Down Expand Up @@ -364,6 +366,7 @@ bool QgsGPXProvider::nextFeature( QgsFeature& feature )
result = true;

feature.setValid( true );
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups

// add attributes if they are wanted
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
Expand Down
1 change: 1 addition & 0 deletions src/providers/grass/qgsgrassprovider.cpp
Expand Up @@ -343,6 +343,7 @@ bool QgsGrassProvider::nextFeature( QgsFeature& feature )

feature.setFeatureId( id );
feature.clearAttributeMap();
feature.setFieldMap( &fields() ); // allow name-based attribute lookups

// TODO int may be 64 bits (memcpy)
if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) ) /* points or lines */
Expand Down
2 changes: 2 additions & 0 deletions src/providers/memory/qgsmemoryprovider.cpp
Expand Up @@ -287,6 +287,7 @@ bool QgsMemoryProvider::nextFeature( QgsFeature& feature )
feature = mSelectIterator.value();
mSelectIterator++;
feature.setValid( true );
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
}

return hasFeature;
Expand All @@ -308,6 +309,7 @@ bool QgsMemoryProvider::featureAtId( QgsFeatureId featureId,

feature = *it;
feature.setValid( true );
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
return true;
}

Expand Down
1 change: 1 addition & 0 deletions src/providers/mssql/qgsmssqlprovider.cpp
Expand Up @@ -537,6 +537,7 @@ bool QgsMssqlProvider::nextFeature( QgsFeature& feature )
}

feature.setValid( true );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
return true;
}
return false;
Expand Down
2 changes: 2 additions & 0 deletions src/providers/ogr/qgsogrprovider.cpp
Expand Up @@ -639,6 +639,7 @@ bool QgsOgrProvider::featureAtId( QgsFeatureId featureId,
if ( !fet )
return false;

feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
feature.setFeatureId( OGR_F_GetFID( fet ) );
feature.clearAttributeMap();
// skip features without geometry
Expand Down Expand Up @@ -714,6 +715,7 @@ bool QgsOgrProvider::nextFeature( QgsFeature& feature )
feature.setFeatureId( OGR_F_GetFID( fet ) );
feature.clearAttributeMap();
feature.setTypeName( featureTypeName );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups

/* fetch geometry */
if ( mFetchGeom || mUseIntersect )
Expand Down
2 changes: 2 additions & 0 deletions src/providers/osm/osmprovider.cpp
Expand Up @@ -651,6 +651,7 @@ bool QgsOSMDataProvider::fetchNode( QgsFeature& feature, sqlite3_stmt* stmt, boo

feature.setFeatureId( selId );
feature.setValid( true );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
return true;
}

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

Expand Down
2 changes: 2 additions & 0 deletions src/providers/postgres/qgspostgresprovider.cpp
Expand Up @@ -672,6 +672,7 @@ bool QgsPostgresProvider::nextFeature( QgsFeature& feature )
mFetched++;

feature.setValid( true );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
return true;
}

Expand Down Expand Up @@ -877,6 +878,7 @@ bool QgsPostgresProvider::featureAtId( QgsFeatureId featureId, QgsFeature& featu
mConnectionRO->closeCursor( cursorName );

feature.setValid( gotit );
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups

#if 0
if ( gotit )
Expand Down
2 changes: 2 additions & 0 deletions src/providers/spatialite/qgsspatialiteprovider.cpp
Expand Up @@ -705,6 +705,7 @@ bool QgsSpatiaLiteProvider::featureAtId( QgsFeatureId featureId, QgsFeature & fe

sqlite3_finalize( stmt );

feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
feature.setValid( true );
return true;
}
Expand All @@ -731,6 +732,7 @@ bool QgsSpatiaLiteProvider::nextFeature( QgsFeature & feature )
return false;
}

feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
feature.setValid( true );
return true;
}
Expand Down
1 change: 1 addition & 0 deletions src/providers/sqlanywhere/qgssqlanywhereprovider.cpp
Expand Up @@ -315,6 +315,7 @@ QgsSqlAnywhereProvider::nextFeature( QgsFeature & feature, SqlAnyStatement *stmt

if ( ok )
{
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
// iterate mAttributesToFetch
feature.clearAttributeMap();
for ( QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin()
Expand Down
1 change: 1 addition & 0 deletions src/providers/wfs/qgswfsprovider.cpp
Expand Up @@ -172,6 +172,7 @@ void QgsWFSProvider::copyFeature( QgsFeature* f, QgsFeature& feature, bool fetch
//id and valid
feature.setValid( true );
feature.setFeatureId( f->id() );
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
}

bool QgsWFSProvider::featureAtId( QgsFeatureId featureId,
Expand Down

0 comments on commit b863ca1

Please sign in to comment.