Skip to content

Commit 945be40

Browse files
committedJun 15, 2014
wfs provider: make wfs non-cached mode work (fixes #10413)
TODO: refactoring
1 parent 37a0428 commit 945be40

File tree

6 files changed

+121
-29
lines changed

6 files changed

+121
-29
lines changed
 

‎src/core/qgsvectorlayer.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,6 @@ void QgsVectorLayer::drawLabels( QgsRenderContext& rendererContext )
388388
}
389389
}
390390

391-
392-
393-
394391
void QgsVectorLayer::reload()
395392
{
396393
if ( mDataProvider )
@@ -408,9 +405,6 @@ bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
408405
{
409406
QgsVectorLayerRenderer renderer( this, rendererContext );
410407
return renderer.render();
411-
412-
413-
414408
}
415409

416410
void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter& p, QgsVectorLayer::VertexMarkerType type, int m )

‎src/providers/wfs/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ SET (WFS_MOC_HDRS
1414
qgswfscapabilities.h
1515
qgswfsdataitems.h
1616
qgswfsprovider.h
17+
qgswfsfeatureiterator.h
1718
qgswfssourceselect.h
1819
)
1920

‎src/providers/wfs/qgswfsfeatureiterator.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ void QgsWFSFeatureIterator::copyFeature( const QgsFeature* f, QgsFeature& featur
150150
// -------------------------
151151

152152
QgsWFSFeatureSource::QgsWFSFeatureSource( const QgsWFSProvider* p )
153-
: mFields( p->mFields )
153+
: QObject(( QgsWFSProvider* ) p )
154+
, mFields( p->mFields )
154155
, mFeatures( p->mFeatures )
155156
, mSpatialIndex( p->mSpatialIndex ? new QgsSpatialIndex( *p->mSpatialIndex ) : 0 ) // just shallow copy
156157
{
@@ -163,5 +164,7 @@ QgsWFSFeatureSource::~QgsWFSFeatureSource()
163164

164165
QgsFeatureIterator QgsWFSFeatureSource::getFeatures( const QgsFeatureRequest& request )
165166
{
167+
if ( request.filterType() == QgsFeatureRequest::FilterRect )
168+
emit extentRequested( request.filterRect() );
166169
return QgsFeatureIterator( new QgsWFSFeatureIterator( this, false, request ) );
167170
}

‎src/providers/wfs/qgswfsfeatureiterator.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,19 @@ class QgsSpatialIndex;
2222
typedef QMap<QgsFeatureId, QgsFeature*> QgsFeaturePtrMap;
2323

2424

25-
class QgsWFSFeatureSource : public QgsAbstractFeatureSource
25+
class QgsWFSFeatureSource : public QObject, public QgsAbstractFeatureSource
2626
{
27+
Q_OBJECT
28+
2729
public:
2830
QgsWFSFeatureSource( const QgsWFSProvider* p );
2931
~QgsWFSFeatureSource();
3032

3133
QgsFeatureIterator getFeatures( const QgsFeatureRequest& request );
3234

35+
signals:
36+
void extentRequested( const QgsRectangle & );
37+
3338
protected:
3439

3540
QgsFields mFields;
@@ -57,7 +62,6 @@ class QgsWFSFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsWFS
5762
private:
5863
QList<QgsFeatureId> mSelectedFeatures;
5964
QList<QgsFeatureId>::const_iterator mFeatureIterator;
60-
6165
};
6266

6367
#endif // QGSWFSFEATUREITERATOR_H

‎src/providers/wfs/qgswfsprovider.cpp

Lines changed: 94 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#include <QUrl>
4444
#include <QWidget>
4545
#include <QPair>
46+
#include <QTimer>
47+
4648
#include <cfloat>
4749

4850
static const QString TEXT_PROVIDER_KEY = "WFS";
@@ -62,9 +64,12 @@ QgsWFSProvider::QgsWFSProvider( const QString& uri )
6264
, mSourceCRS( 0 )
6365
, mFeatureCount( 0 )
6466
, mValid( true )
67+
, mPendingRetrieval( false )
68+
#if 0
6569
, mLayer( 0 )
6670
, mGetRenderedOnly( false )
6771
, mInitGro( false )
72+
#endif
6873
{
6974
mSpatialIndex = 0;
7075
if ( uri.isEmpty() )
@@ -115,7 +120,8 @@ QgsWFSProvider::QgsWFSProvider( const QString& uri )
115120
setDataSourceUri( bkUri );
116121
}
117122

118-
if ( ! uri.contains( "BBOX=" ) )
123+
mCached = !uri.contains( "BBOX=" );
124+
if ( mCached )
119125
{ //"Cache Features" option; get all features in layer immediately
120126
reloadData();
121127
} //otherwise, defer feature retrieval until layer is first rendered
@@ -124,6 +130,8 @@ QgsWFSProvider::QgsWFSProvider( const QString& uri )
124130
{
125131
getLayerCapabilities();
126132
}
133+
134+
qRegisterMetaType<QgsRectangle>( "QgsRectangle" );
127135
}
128136

129137
QgsWFSProvider::~QgsWFSProvider()
@@ -134,15 +142,22 @@ QgsWFSProvider::~QgsWFSProvider()
134142

135143
QgsAbstractFeatureSource* QgsWFSProvider::featureSource() const
136144
{
137-
return new QgsWFSFeatureSource( this );
145+
QgsWFSFeatureSource *fs = new QgsWFSFeatureSource( this );
146+
connect( fs, SIGNAL( extentRequested( const QgsRectangle & ) ),
147+
this, SLOT( extendExtent( const QgsRectangle & ) ) );
148+
return fs;
138149
}
139150

140151
void QgsWFSProvider::reloadData()
141152
{
153+
mPendingRetrieval = false;
142154
deleteData();
143155
delete mSpatialIndex;
144156
mSpatialIndex = new QgsSpatialIndex();
145157
mValid = !getFeature( dataSourceUri() );
158+
159+
if ( !mCached )
160+
emit dataChanged();
146161
}
147162

148163
void QgsWFSProvider::deleteData()
@@ -193,6 +208,7 @@ bool QgsWFSProvider::isValid()
193208

194209
QgsFeatureIterator QgsWFSProvider::getFeatures( const QgsFeatureRequest& request )
195210
{
211+
#if 0
196212
if ( !( request.flags() & QgsFeatureRequest::NoGeometry ) )
197213
{
198214
QgsRectangle rect = request.filterRect();
@@ -261,7 +277,8 @@ QgsFeatureIterator QgsWFSProvider::getFeatures( const QgsFeatureRequest& request
261277
}
262278

263279
}
264-
return QgsFeatureIterator( new QgsWFSFeatureIterator( new QgsWFSFeatureSource( this ), true, request ) );
280+
#endif
281+
return new QgsWFSFeatureIterator( new QgsWFSFeatureSource( this ), true, request );
265282
}
266283

267284
int QgsWFSProvider::getFeature( const QString& uri )
@@ -658,7 +675,7 @@ int QgsWFSProvider::getFeatureGET( const QString& uri, const QString& geometryAt
658675
QString typeName = parameterFromUrl( "typename" );
659676
QgsGml dataReader( typeName, geometryAttribute, mFields );
660677

661-
QObject::connect( &dataReader, SIGNAL( dataProgressAndSteps( int , int ) ), this, SLOT( handleWFSProgressMessage( int, int ) ) );
678+
connect( &dataReader, SIGNAL( dataProgressAndSteps( int , int ) ), this, SLOT( handleWFSProgressMessage( int, int ) ) );
662679

663680
//also connect to statusChanged signal of qgisapp (if it exists)
664681
QWidget* mainWindow = 0;
@@ -675,14 +692,15 @@ int QgsWFSProvider::getFeatureGET( const QString& uri, const QString& geometryAt
675692

676693
if ( mainWindow )
677694
{
678-
QObject::connect( this, SIGNAL( dataReadProgressMessage( QString ) ), mainWindow, SLOT( showStatusMessage( QString ) ) );
695+
connect( this, SIGNAL( dataReadProgressMessage( QString ) ), mainWindow, SLOT( showStatusMessage( QString ) ) );
679696
}
680697

681698
//if ( dataReader.getWFSData() != 0 )
682699
QUrl getFeatureUrl( uri );
683700
getFeatureUrl.removeQueryItem( "username" );
684701
getFeatureUrl.removeQueryItem( "password" );
685-
if ( dataReader.getFeatures( getFeatureUrl.toString(), &mWKBType, &mExtent, mAuth.mUserName, mAuth.mPassword ) != 0 )
702+
QgsRectangle extent;
703+
if ( dataReader.getFeatures( getFeatureUrl.toString(), &mWKBType, mCached ? &mExtent : &extent, mAuth.mUserName, mAuth.mPassword ) != 0 )
686704
{
687705
QgsDebugMsg( "getWFSData returned with error" );
688706
return 1;
@@ -691,7 +709,6 @@ int QgsWFSProvider::getFeatureGET( const QString& uri, const QString& geometryAt
691709
mIdMap = dataReader.idsMap();
692710

693711
QgsDebugMsg( QString( "feature count after request is: %1" ).arg( mFeatures.size() ) );
694-
QgsDebugMsg( QString( "mExtent after request is: %1" ).arg( mExtent.toString() ) );
695712

696713
if ( mWKBType != QGis::WKBNoGeometry )
697714
{
@@ -726,7 +743,8 @@ int QgsWFSProvider::getFeatureFILE( const QString& uri, const QString& geometryA
726743

727744
QDomElement featureCollectionElement = gmlDoc.documentElement();
728745
//get and set Extent
729-
if ( mWKBType != QGis::WKBNoGeometry && getExtentFromGML2( &mExtent, featureCollectionElement ) != 0 )
746+
QgsRectangle extent;
747+
if ( mWKBType != QGis::WKBNoGeometry && getExtentFromGML2( mCached ? &mExtent : &extent, featureCollectionElement ) != 0 )
730748
{
731749
return 3;
732750
}
@@ -1102,7 +1120,6 @@ int QgsWFSProvider::getExtentFromGML2( QgsRectangle* extent, const QDomElement&
11021120

11031121
int QgsWFSProvider::setCRSFromGML2( const QDomElement& wfsCollectionElement )
11041122
{
1105-
QgsDebugMsg( "entering." );
11061123
//search <gml:boundedBy>
11071124
QDomNodeList boundedByList = wfsCollectionElement.elementsByTagNameNS( GML_NAMESPACE, "boundedBy" );
11081125
if ( boundedByList.size() < 1 )
@@ -1523,6 +1540,26 @@ void QgsWFSProvider::getLayerCapabilities()
15231540
QString name = featureTypeList.at( i ).firstChildElement( "Name" ).text();
15241541
if ( name == thisLayerName )
15251542
{
1543+
if ( !mCached && mExtent.isEmpty() )
1544+
{
1545+
QDomElement e = featureTypeList.at( i ).firstChildElement( "LatLongBoundingBox" );
1546+
if ( !e.isNull() )
1547+
{
1548+
QgsRectangle r( e.attribute( "minx" ).toDouble(), e.attribute( "miny" ).toDouble(),
1549+
e.attribute( "maxx" ).toDouble(), e.attribute( "maxy" ).toDouble() );
1550+
QgsCoordinateReferenceSystem src;
1551+
src.createFromOgcWmsCrs( "CRS:84" );
1552+
QgsCoordinateTransform ct( src, mSourceCRS );
1553+
1554+
QgsDebugMsg( "latlon ext:" + r.toString() );
1555+
QgsDebugMsg( "src:" + src.authid() );
1556+
QgsDebugMsg( "dst:" + mSourceCRS.authid() );
1557+
1558+
mExtent = ct.transformBoundingBox( r, QgsCoordinateTransform::ForwardTransform );
1559+
1560+
QgsDebugMsg( "layer ext:" + mExtent.toString() );
1561+
}
1562+
}
15261563
appendSupportedOperations( featureTypeList.at( i ).firstChildElement( "Operations" ), capabilities );
15271564
break;
15281565
}
@@ -1558,6 +1595,7 @@ void QgsWFSProvider::appendSupportedOperations( const QDomElement& operationsEle
15581595
}
15591596
}
15601597

1598+
#if 0
15611599
//initialization for getRenderedOnly option
15621600
//(formerly "Only request features overlapping the current view extent")
15631601
bool QgsWFSProvider::initGetRenderedOnly( const QgsRectangle &rect )
@@ -1585,6 +1623,7 @@ bool QgsWFSProvider::initGetRenderedOnly( const QgsRectangle &rect )
15851623
}
15861624
return true;
15871625
}
1626+
#endif
15881627

15891628
QGis::WkbType QgsWFSProvider::geomTypeFromPropertyType( QString attName, QString propType )
15901629
{
@@ -1617,33 +1656,73 @@ void QgsWFSProvider::handleException( const QDomDocument& serverResponse )
16171656
QDomElement exceptionElem = serverResponse.documentElement();
16181657
if ( exceptionElem.isNull() )
16191658
{
1620-
pushError( QObject::tr( "empty response" ) );
1659+
pushError( tr( "empty response" ) );
16211660
return;
16221661
}
16231662

16241663
if ( exceptionElem.tagName() == "ServiceExceptionReport" )
16251664
{
1626-
pushError( QObject::tr( "WFS service exception:%1" ).arg( exceptionElem.firstChildElement( "ServiceException" ).text() ) );
1665+
pushError( tr( "WFS service exception:%1" ).arg( exceptionElem.firstChildElement( "ServiceException" ).text() ) );
16271666
return;
16281667
}
16291668

16301669
if ( exceptionElem.tagName() == "WFS_TransactionResponse" )
16311670
{
1632-
pushError( QObject::tr( "unsuccessful service response: %1" ).arg( exceptionElem.firstChildElement( "TransactionResult" ).firstChildElement( "Message" ).text() ) );
1671+
pushError( tr( "unsuccessful service response: %1" ).arg( exceptionElem.firstChildElement( "TransactionResult" ).firstChildElement( "Message" ).text() ) );
16331672
return;
16341673
}
16351674

16361675
if ( exceptionElem.tagName() == "ExceptionReport" )
16371676
{
16381677
QDomElement exception = exceptionElem.firstChildElement( "Exception" );
1639-
pushError( QObject::tr( "WFS exception report (code=%1 text=%2)" )
1640-
.arg( exception.attribute( "exceptionCode", QObject::tr( "missing" ) ) )
1678+
pushError( tr( "WFS exception report (code=%1 text=%2)" )
1679+
.arg( exception.attribute( "exceptionCode", tr( "missing" ) ) )
16411680
.arg( exception.firstChildElement( "ExceptionText" ).text() )
16421681
);
16431682
return;
16441683
}
16451684

1646-
pushError( QObject::tr( "unhandled response: %1" ).arg( exceptionElem.tagName() ) );
1685+
pushError( tr( "unhandled response: %1" ).arg( exceptionElem.tagName() ) );
1686+
}
1687+
1688+
void QgsWFSProvider::extendExtent( const QgsRectangle &extent )
1689+
{
1690+
if ( mCached )
1691+
return;
1692+
1693+
QgsRectangle r( mExtent.intersect( &extent ) );
1694+
1695+
if ( mGetExtent.contains( r ) )
1696+
return;
1697+
1698+
if ( mGetExtent.isEmpty() )
1699+
{
1700+
mGetExtent = r;
1701+
}
1702+
else if ( qgsDoubleNear( mGetExtent.xMinimum(), r.xMinimum() ) &&
1703+
qgsDoubleNear( mGetExtent.yMinimum(), r.yMinimum() ) &&
1704+
qgsDoubleNear( mGetExtent.xMaximum(), r.xMaximum() ) &&
1705+
qgsDoubleNear( mGetExtent.yMaximum(), r.yMaximum() ) )
1706+
{
1707+
return;
1708+
}
1709+
else
1710+
{
1711+
mGetExtent.combineExtentWith( &r );
1712+
}
1713+
1714+
setDataSourceUri( dataSourceUri().replace( QRegExp( "BBOX=[^&]*" ),
1715+
QString( "BBOX=%1,%2,%3,%4" )
1716+
.arg( qgsDoubleToString( mGetExtent.xMinimum() ) )
1717+
.arg( qgsDoubleToString( mGetExtent.yMinimum() ) )
1718+
.arg( qgsDoubleToString( mGetExtent.xMaximum() ) )
1719+
.arg( qgsDoubleToString( mGetExtent.yMaximum() ) ) ) );
1720+
1721+
if ( !mPendingRetrieval )
1722+
{
1723+
mPendingRetrieval = true;
1724+
QTimer::singleShot( 100, this, SLOT( reloadData() ) );
1725+
}
16471726
}
16481727

16491728
QGISEXTERN QgsWFSProvider* classFactory( const QString *uri )

‎src/providers/wfs/qgswfsprovider.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct QgsWFSAuthorization
5454
};
5555

5656
/**A provider reading features from a WFS server*/
57-
class QgsWFSProvider: public QgsVectorDataProvider
57+
class QgsWFSProvider : public QgsVectorDataProvider
5858
{
5959
Q_OBJECT
6060
public:
@@ -131,17 +131,20 @@ class QgsWFSProvider: public QgsVectorDataProvider
131131
*/
132132
virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map );
133133

134-
/**Reloads the data from the source. Needs to be implemented by providers with data caches to
135-
synchronize with changes in the data source*/
136-
virtual void reloadData();
137-
138134
/**Collects information about the field types. Is called internally from QgsWFSProvider ctor. The method delegates the work to request specific ones and gives back the name of the geometry attribute and the thematic attributes with their types*/
139135
int describeFeatureType( const QString& uri, QString& geometryAttribute,
140136
QgsFields& fields, QGis::WkbType& geomType );
141137

138+
public slots:
139+
/**Reloads the data from the source. Needs to be implemented by providers with data caches to
140+
synchronize with changes in the data source*/
141+
virtual void reloadData();
142+
142143
signals:
143144
void dataReadProgressMessage( QString message );
144145

146+
void dataChanged();
147+
145148
private slots:
146149
/**Receives the progress signals from QgsWFSData::dataReadProgress, generates a string
147150
and emits the dataReadProgressMessage signal*/
@@ -150,6 +153,8 @@ class QgsWFSProvider: public QgsVectorDataProvider
150153
/**Sets mNetworkRequestFinished flag to true*/
151154
void networkRequestFinished();
152155

156+
void extendExtent( const QgsRectangle & );
157+
153158
private:
154159
bool mNetworkRequestFinished;
155160
friend class QgsWFSFeatureSource;
@@ -187,16 +192,20 @@ class QgsWFSProvider: public QgsVectorDataProvider
187192
int mFeatureCount;
188193
/**Flag if provider is valid*/
189194
bool mValid;
195+
bool mCached;
196+
bool mPendingRetrieval;
190197
/**Namespace URL of the server (comes from DescribeFeatureDocument)*/
191198
QString mWfsNamespace;
192199
/**Server capabilities for this layer (generated from capabilities document)*/
193200
int mCapabilities;
201+
#if 0
194202
/**GetRenderedOnly: layer asociated with this provider*/
195203
QgsVectorLayer *mLayer;
196204
/**GetRenderedOnly: fetch only features within canvas extent to be rendered*/
197205
bool mGetRenderedOnly;
198206
/**GetRenderedOnly initializaiton flat*/
199207
bool mInitGro;
208+
#endif
200209
/**if GetRenderedOnly, extent specified in WFS getFeatures; else empty (no constraint)*/
201210
QgsRectangle mGetExtent;
202211

@@ -258,8 +267,10 @@ class QgsWFSProvider: public QgsVectorDataProvider
258267
void appendSupportedOperations( const QDomElement& operationsElem, int& capabilities ) const;
259268
/**records provider error*/
260269
void handleException( const QDomDocument& serverResponse );
270+
#if 0
261271
/**Initializes "Cache Features" inactive processing*/
262272
bool initGetRenderedOnly( const QgsRectangle &rect );
273+
#endif
263274
/**Converts DescribeFeatureType schema geometry property type to WKBType*/
264275
QGis::WkbType geomTypeFromPropertyType( QString attName, QString propType );
265276

0 commit comments

Comments
 (0)
Please sign in to comment.