Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Change WFS provider for new vector api
  • Loading branch information
mhugent committed Jan 21, 2013
1 parent 11d5bd3 commit 3e419b9
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 46 deletions.
2 changes: 1 addition & 1 deletion src/providers/CMakeLists.txt
Expand Up @@ -23,7 +23,7 @@ ENDIF (SPATIALITE_FOUND OR WITH_INTERNAL_SPATIALITE)

IF (EXPAT_FOUND)
ADD_SUBDIRECTORY(gpx)
# ADD_SUBDIRECTORY(wfs) # TODO: enable when migrated to new api
ADD_SUBDIRECTORY(wfs)
ENDIF (EXPAT_FOUND)

IF (GRASS_FOUND)
Expand Down
1 change: 1 addition & 0 deletions src/providers/wfs/CMakeLists.txt
Expand Up @@ -7,6 +7,7 @@ SET(WFS_SRCS
qgswfscapabilities.cpp
qgswfsdataitems.cpp
qgswfsdata.cpp
qgswfsfeatureiterator.cpp
qgswfssourceselect.cpp
qgswfsutils.cpp
)
Expand Down
5 changes: 4 additions & 1 deletion src/providers/wfs/qgswfsdata.cpp
Expand Up @@ -186,6 +186,8 @@ void QgsWFSData::startElement( const XML_Char* el, const XML_Char** attr )
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "featureMember" )
{
mCurrentFeature = new QgsFeature( mFeatureCount );
QgsAttributes attributes( mThematicAttributes.size() ); //add empty attributes
mCurrentFeature->setAttributes( attributes );
mParseModeStack.push( QgsWFSData::featureMember );
}
else if ( localName == mTypeName )
Expand Down Expand Up @@ -277,7 +279,8 @@ void QgsWFSData::endElement( const XML_Char* el )
var = QVariant( mStringCash );
break;
}
mCurrentFeature->addAttribute( att_it.value().first, QVariant( mStringCash ) );

mCurrentFeature->setAttribute( att_it.value().first, QVariant( mStringCash ) );
}
}
else if ( localName == mGeometryAttribute )
Expand Down
1 change: 1 addition & 0 deletions src/providers/wfs/qgswfsdata.h
Expand Up @@ -158,6 +158,7 @@ class QgsWFSData: public QObject
/**This contains the character data if an important element has been encountered*/
QString mStringCash;
QgsFeature* mCurrentFeature;
QVector<QVariant> mCurrentAttributes; //attributes of current feature
QString mCurrentFeatureId;
int mFeatureCount;
/**The total WKB for a feature*/
Expand Down
71 changes: 71 additions & 0 deletions src/providers/wfs/qgswfsfeatureiterator.cpp
@@ -0,0 +1,71 @@
#include "qgswfsfeatureiterator.h"
#include "qgsspatialindex.h"
#include "qgswfsprovider.h"

QgsWFSFeatureIterator::QgsWFSFeatureIterator( QgsWFSProvider* provider, const QgsFeatureRequest& request ):
QgsAbstractFeatureIterator( request ), mProvider( provider )
{
//select ids
//get iterator
if ( !mProvider )
{
return;
}

switch ( request.filterType() )
{
case QgsFeatureRequest::FilterRect:
if ( mProvider->mSpatialIndex )
{
mSelectedFeatures = mProvider->mSpatialIndex->intersects( request.filterRect() );
}
break;
case QgsFeatureRequest::FilterFid:
mSelectedFeatures.push_back( request.filterFid() );
break;
case QgsFeatureRequest::FilterNone:
mSelectedFeatures = mProvider->mFeatures.keys();
default: //QgsFeatureRequest::FilterNone
mSelectedFeatures = mProvider->mFeatures.keys();
}

mFeatureIterator = mSelectedFeatures.constBegin();
}

QgsWFSFeatureIterator::~QgsWFSFeatureIterator()
{

}

bool QgsWFSFeatureIterator::nextFeature( QgsFeature& f )
{
if ( !mProvider )
{
return false;
}

if ( mFeatureIterator == mSelectedFeatures.constEnd() )
{
return false;
}

QMap<QgsFeatureId, QgsFeature* >::iterator it = mProvider->mFeatures.find( *mFeatureIterator );
if ( it == mProvider->mFeatures.end() )
{
return false;
}
QgsFeature* fet = it.value();
mProvider->copyFeature( fet, f, !( mRequest.flags() & QgsFeatureRequest::NoGeometry ), mRequest.subsetOfAttributes() );
++mFeatureIterator;
return true;
}

bool QgsWFSFeatureIterator::rewind()
{
return false;
}

bool QgsWFSFeatureIterator::close()
{
return false;
}
24 changes: 24 additions & 0 deletions src/providers/wfs/qgswfsfeatureiterator.h
@@ -0,0 +1,24 @@
#ifndef QGSWFSFEATUREITERATOR_H
#define QGSWFSFEATUREITERATOR_H

#include "qgsfeatureiterator.h"

class QgsWFSProvider;

class QgsWFSFeatureIterator: public QgsAbstractFeatureIterator
{
public:
QgsWFSFeatureIterator( QgsWFSProvider* provider, const QgsFeatureRequest& request );
~QgsWFSFeatureIterator();

bool nextFeature( QgsFeature& f );
bool rewind();
bool close();

private:
QgsWFSProvider* mProvider;
QList<QgsFeatureId> mSelectedFeatures;
QList<QgsFeatureId>::const_iterator mFeatureIterator;
};

#endif // QGSWFSFEATUREITERATOR_H
138 changes: 103 additions & 35 deletions src/providers/wfs/qgswfsprovider.cpp
Expand Up @@ -25,6 +25,7 @@
#include "qgsgeometry.h"
#include "qgscoordinatereferencesystem.h"
#include "qgswfsdata.h"
#include "qgswfsfeatureiterator.h"
#include "qgswfsprovider.h"
#include "qgsspatialindex.h"
#include "qgslogger.h"
Expand Down Expand Up @@ -164,15 +165,16 @@ void QgsWFSProvider::copyFeature( QgsFeature* f, QgsFeature& feature, bool fetch

//and the attributes
const QgsAttributes& attributes = f->attributes();
feature.setAttributes( attributes );
for ( QgsAttributeList::const_iterator it = fetchAttributes.begin(); it != fetchAttributes.end(); ++it )
{
feature.addAttribute( *it, attributes[*it] );
feature.setAttribute( *it, attributes[*it] );
}

//id and valid
feature.setValid( true );
feature.setFeatureId( f->id() );
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
feature.setFields( &mFields ); // allow name-based attribute lookups
}

bool QgsWFSProvider::featureAtId( QgsFeatureId featureId,
Expand Down Expand Up @@ -246,7 +248,7 @@ long QgsWFSProvider::featureCount() const
return mFeatureCount;
}

const QgsFieldMap & QgsWFSProvider::fields() const
const QgsFields& QgsWFSProvider::fields() const
{
return mFields;
}
Expand All @@ -271,6 +273,79 @@ bool QgsWFSProvider::isValid()
return mValid;
}

QgsFeatureIterator QgsWFSProvider::getFeatures( const QgsFeatureRequest& request )
{
if ( ! request.flags() & QgsFeatureRequest::NoGeometry )
{
QgsRectangle rect = request.filterRect();
if ( !rect.isEmpty() )
{
QString dsURI = dataSourceUri();
//first time through, initialize GetRenderedOnly args
//ctor cannot initialize because layer object not available then
if ( ! mInitGro )
{ //did user check "Cache Features" in WFS layer source selection?
if ( dsURI.contains( "BBOX" ) )
{ //no: initialize incremental getFeature
if ( initGetRenderedOnly( rect ) )
{
mGetRenderedOnly = true;
}
else
{ //initialization failed;
QgsDebugMsg( QString( "GetRenderedOnly initialization failed; incorrect operation may occur\n%1" )
.arg( dataSourceUri() ) );
QMessageBox( QMessageBox::Warning, "Non-Cached layer initialization failed!",
QString( "Incorrect operation may occur:\n%1" ).arg( dataSourceUri() ) );
}
}
mInitGro = true;
}

if ( mGetRenderedOnly )
{ //"Cache Features" was not selected for this layer
//has rendered extent expanded beyond last-retrieved WFS extent?
//NB: "intersect" instead of "contains" tolerates rounding errors;
// avoids unnecessary second fetch on zoom-in/zoom-out sequences
QgsRectangle olap( rect );
olap = olap.intersect( &mGetExtent );
if ( doubleNear( rect.width(), olap.width() ) && doubleNear( rect.height(), olap.height() ) )
{ //difference between canvas and layer extents is within rounding error: do not re-fetch
QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: no fetch required" ).arg( mLayer->name() ) );
}
else
{ //combined old and new extents might speed up local panning & zooming
mGetExtent.combineExtentWith( &rect );
//but see if the combination is useless or too big
double pArea = mGetExtent.width() * mGetExtent.height();
double cArea = rect.width() * rect.height();
if ( olap.isEmpty() || pArea > ( cArea * 4.0 ) )
{ //new canvas extent does not overlap or combining old and new extents would
//fetch > 4 times the area to be rendered; get only what will be rendered
mGetExtent = rect;
}
QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: fetching extent %2" )
.arg( mLayer->name(), mGetExtent.asWktCoordinates() ) );
dsURI = dsURI.replace( QRegExp( "BBOX=[^&]*" ),
QString( "BBOX=%1,%2,%3,%4" )
.arg( mGetExtent.xMinimum(), 0, 'f' )
.arg( mGetExtent.yMinimum(), 0, 'f' )
.arg( mGetExtent.xMaximum(), 0, 'f' )
.arg( mGetExtent.yMaximum(), 0, 'f' ) );
//TODO: BBOX may not be combined with FILTER. WFS spec v. 1.1.0, sec. 14.7.3 ff.
// if a FILTER is present, the BBOX must be merged into it, capabilities permitting.
// Else one criterion must be abandoned and the user warned. [WBC 111221]
setDataSourceUri( dsURI );
reloadData();
mLayer->updateExtents();
}
}
}

}
return QgsFeatureIterator( new QgsWFSFeatureIterator( this, request ) );
}

void QgsWFSProvider::select( QgsAttributeList fetchAttributes,
QgsRectangle rect,
bool fetchGeometry,
Expand Down Expand Up @@ -399,21 +474,23 @@ bool QgsWFSProvider::addFeatures( QgsFeatureList &flist )
QDomElement featureElem = transactionDoc.createElementNS( mWfsNamespace, tname );

//add thematic attributes
QgsAttributeMap featureAttributes = featureIt->attributeMap();
QgsFieldMap::const_iterator fieldIt = mFields.constBegin();
for ( ; fieldIt != mFields.constEnd(); ++fieldIt )
const QgsFields* fields = featureIt->fields();
if ( !fields )
{
continue;
}

QgsAttributes featureAttributes = featureIt->attributes();
int nAttrs = featureAttributes.size();
for ( int i = 0; i < nAttrs; ++i )
{
QgsAttributeMap::const_iterator valueIt = featureAttributes.find( fieldIt.key() );
if ( valueIt != featureAttributes.constEnd() )
const QVariant& value = featureAttributes.at( i );
if ( value.isValid() && !value.isNull() )
{
QVariant fieldValue = valueIt.value();
if ( fieldValue.isValid() && !fieldValue.isNull() )
{
QDomElement fieldElem = transactionDoc.createElementNS( mWfsNamespace, fieldIt.value().name() );
QDomText fieldText = transactionDoc.createTextNode( fieldValue.toString() );
fieldElem.appendChild( fieldText );
featureElem.appendChild( fieldElem );
}
QDomElement fieldElem = transactionDoc.createElementNS( mWfsNamespace, fields->field( i ).name() );
QDomText fieldText = transactionDoc.createTextNode( value.toString() );
fieldElem.appendChild( fieldText );
featureElem.appendChild( fieldElem );
}
}

Expand Down Expand Up @@ -633,8 +710,6 @@ bool QgsWFSProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
return false;
}

const QgsFieldMap& fieldMap = fields();

//create <Transaction> xml
QDomDocument transactionDoc;
QDomElement transactionElem = createTransactionElement( transactionDoc );
Expand All @@ -656,14 +731,7 @@ bool QgsWFSProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
QgsAttributeMap::const_iterator attMapIt = attIt.value().constBegin();
for ( ; attMapIt != attIt.value().constEnd(); ++attMapIt )
{
QString fieldName;
QgsFieldMap::const_iterator fieldIt = fieldMap.find( attMapIt.key() );
if ( fieldIt == fieldMap.constEnd() )
{
continue;
}
fieldName = fieldIt.value().name();

QString fieldName = mFields.at( attMapIt.key() ).name();
QDomElement propertyElem = transactionDoc.createElementNS( "http://www.opengis.net/wfs", "Property" );

QDomElement nameElem = transactionDoc.createElementNS( "http://www.opengis.net/wfs", "Name" );
Expand Down Expand Up @@ -730,7 +798,7 @@ bool QgsWFSProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
}

int QgsWFSProvider::describeFeatureType( const QString& uri, QString& geometryAttribute,
QgsFieldMap& fields, QGis::WkbType& geomType )
QgsFields& fields, QGis::WkbType& geomType )
//NB: also called from QgsWFSSourceSelect::on_treeWidget_itemDoubleClicked() to build filters.
// a temporary provider object is constructed with a null URI, which bypasses much provider
// instantiation logic: refresh(), getFeature(), etc. therefore, many provider class members
Expand Down Expand Up @@ -759,9 +827,9 @@ int QgsWFSProvider::getFeatureGET( const QString& uri, const QString& geometryAt

//allows fast searchings with attribute name. Also needed is attribute Index and type infos
QMap<QString, QPair<int, QgsField> > thematicAttributes;
for ( QgsFieldMap::const_iterator it = mFields.begin(); it != mFields.end(); ++it )
for ( int i = 0; i < mFields.count(); ++i )
{
thematicAttributes.insert( it.value().name(), qMakePair( it.key(), it.value() ) );
thematicAttributes.insert( mFields.at( i ).name(), qMakePair( i, mFields.at( i ) ) );
}

QgsWFSData dataReader( uri, &mExtent, mFeatures, mIdMap, geometryAttribute, thematicAttributes, &mWKBType );
Expand Down Expand Up @@ -843,7 +911,7 @@ int QgsWFSProvider::getFeatureFILE( const QString& uri, const QString& geometryA
return 0;
}

int QgsWFSProvider::describeFeatureTypeGET( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType )
int QgsWFSProvider::describeFeatureTypeGET( const QString& uri, QString& geometryAttribute, QgsFields& fields, QGis::WkbType& geomType )
{
if ( !mNetworkRequestFinished )
{
Expand Down Expand Up @@ -887,7 +955,7 @@ void QgsWFSProvider::networkRequestFinished()
mNetworkRequestFinished = true;
}

int QgsWFSProvider::describeFeatureTypeFile( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType )
int QgsWFSProvider::describeFeatureTypeFile( const QString& uri, QString& geometryAttribute, QgsFields& fields, QGis::WkbType& geomType )
{
//first look in the schema file
QString noExtension = uri;
Expand Down Expand Up @@ -928,7 +996,7 @@ int QgsWFSProvider::describeFeatureTypeFile( const QString& uri, QString& geomet
return 0;
}

int QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType )
int QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc, QString& geometryAttribute, QgsFields& fields, QGis::WkbType& geomType )
{
//get the <schema> root element
QDomNodeList schemaNodeList = schemaDoc.elementsByTagNameNS( "http://www.w3.org/2001/XMLSchema", "schema" );
Expand Down Expand Up @@ -1027,7 +1095,7 @@ int QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc, QString&
{
attributeType = QVariant::LongLong;
}
fields[fields.size()] = QgsField( name, attributeType, type );
fields.append( QgsField( name, attributeType, type ) );
}
}
if ( !foundGeometryAttribute )
Expand Down Expand Up @@ -1281,11 +1349,11 @@ int QgsWFSProvider::getFeaturesFromGML2( const QDomElement& wfsCollectionElement
{
if ( numeric )
{
f->addAttribute( attr++, QVariant( currentAttributeElement.text().toDouble() ) );
f->setAttribute( attr++, QVariant( currentAttributeElement.text().toDouble() ) );
}
else
{
f->addAttribute( attr++, QVariant( currentAttributeElement.text() ) );
f->setAttribute( attr++, QVariant( currentAttributeElement.text() ) );
}
}
else //a geometry attribute
Expand Down

0 comments on commit 3e419b9

Please sign in to comment.