Skip to content

Commit 945be40

Browse files
committed
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

-6
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

+1
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

+4-1
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

+6-2
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

+94-15
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 )

0 commit comments

Comments
 (0)