incremental-wsf-rev2.patch
src/app/qgisapp.cpp | ||
---|---|---|
2437 | 2437 |
return; |
2438 | 2438 |
} |
2439 | 2439 | |
2440 |
// Fudge for now |
|
2441 | 2440 |
QgsDebugMsg( "about to addWfsLayer" ); |
2442 | 2441 | |
2443 | 2442 |
// TODO: QDialog for now, switch to QWidget in future |
... | ... | |
2450 | 2449 |
connect( wfss , SIGNAL( addWfsLayer( QString, QString ) ), |
2451 | 2450 |
this , SLOT( addWfsLayer( QString, QString ) ) ); |
2452 | 2451 | |
2453 |
wfss->setProperty( "MapExtent", mMapCanvas->extent().toString() ); //hack to reenable wfs with extent setting |
|
2452 |
//reenable wfs with extent setting: pass canvas info to source select |
|
2453 |
wfss->setProperty( "MapExtent", mMapCanvas->extent().toString() ); |
|
2454 |
if ( mMapCanvas->mapRenderer()->hasCrsTransformEnabled() ) |
|
2455 |
{ //if "on the fly" reprojection is active, pass canvas CRS |
|
2456 |
wfss->setProperty( "MapCRS", mMapCanvas->mapRenderer()->destinationCrs().authid() ); |
|
2457 |
} |
|
2454 | 2458 | |
2455 | 2459 |
bool bkRenderFlag = mMapCanvas->renderFlag(); |
2456 | 2460 |
mMapCanvas->setRenderFlag( false ); |
src/providers/wfs/qgswfsdata.cpp | ||
---|---|---|
101 | 101 | |
102 | 102 |
if ( mainWindow ) |
103 | 103 |
{ |
104 |
progressDialog = new QProgressDialog( tr( "Loading WFS data" ), tr( "Abort" ), 0, 0, mainWindow );
|
|
104 |
progressDialog = new QProgressDialog( tr( "Loading WFS data\n%1" ).arg( mTypeName ), tr( "Abort" ), 0, 0, mainWindow );
|
|
105 | 105 |
progressDialog->setWindowModality( Qt::ApplicationModal ); |
106 | 106 |
connect( this, SIGNAL( dataReadProgress( int ) ), progressDialog, SLOT( setValue( int ) ) ); |
107 | 107 |
connect( this, SIGNAL( totalStepsUpdate( int ) ), progressDialog, SLOT( setMaximum( int ) ) ); |
src/providers/wfs/qgswfsprovider.cpp | ||
---|---|---|
17 | 17 | |
18 | 18 |
#define WFS_THRESHOLD 200 |
19 | 19 | |
20 |
#include "qgis.h" |
|
20 | 21 |
#include "qgsapplication.h" |
22 |
#include "qgsmaplayerregistry.h" |
|
21 | 23 |
#include "qgsfeature.h" |
22 | 24 |
#include "qgsfield.h" |
23 | 25 |
#include "qgsgeometry.h" |
... | ... | |
47 | 49 |
QgsWFSProvider::QgsWFSProvider( const QString& uri ) |
48 | 50 |
: QgsVectorDataProvider( uri ), |
49 | 51 |
mNetworkRequestFinished( true ), |
52 |
mGeometryAttribute( 0 ), |
|
50 | 53 |
mEncoding( QgsWFSProvider::GET ), |
51 | 54 |
mUseIntersect( false ), |
55 |
mWKBType( QGis::WKBUnknown ), |
|
52 | 56 |
mSourceCRS( 0 ), |
53 | 57 |
mFeatureCount( 0 ), |
54 |
mValid( true ) |
|
58 |
mValid( true ), |
|
59 |
mLayer( 0 ), |
|
60 |
mGetRenderedOnly( false ), |
|
61 |
mInitGro( false ), |
|
62 |
mGetExtent() |
|
55 | 63 |
{ |
56 | 64 |
mSpatialIndex = 0; |
57 | 65 |
if ( uri.isEmpty() ) |
... | ... | |
60 | 68 |
return; |
61 | 69 |
} |
62 | 70 | |
63 |
reloadData(); |
|
71 |
//Local url or HTTP? [WBC 111221] refactored from getFeature() |
|
72 |
if ( uri.startsWith( "http" ) ) |
|
73 |
{ |
|
74 |
mEncoding = QgsWFSProvider::GET; |
|
75 |
} |
|
76 |
else |
|
77 |
{ |
|
78 |
mEncoding = QgsWFSProvider::FILE; |
|
79 |
} |
|
80 | ||
81 |
//create mSourceCRS from url if possible [WBC 111221] refactored from GetFeatureGET() |
|
82 |
QString srsname = parameterFromUrl( "SRSNAME" ); |
|
83 |
if ( !srsname.isEmpty() ) |
|
84 |
{ |
|
85 |
mSourceCRS.createFromOgcWmsCrs( srsname ); |
|
86 |
} |
|
87 | ||
88 |
//fetch attributes of layer and type of its geometry attribute |
|
89 |
//WBC 111221: extracting geometry type here instead of getFeature allows successful |
|
90 |
//layer creation even when no features are retrieved (due to, e.g., BBOX or FILTER) |
|
91 |
if ( describeFeatureType( uri, mGeometryAttribute, mFields, mWKBType ) ) |
|
92 |
{ |
|
93 |
mValid = false; |
|
94 |
QgsDebugMsg( QString( "describeFeatureType failed, URI=%1" ).arg( uri ) ); |
|
95 |
QMessageBox( QMessageBox::Warning, "DescribeFeatureType failed!", |
|
96 |
QString( "Layer cannot be created from\n%1" ).arg( uri ) ); |
|
97 |
return; |
|
98 |
} |
|
99 | ||
100 |
if ( ! uri.contains("BBOX") ) |
|
101 |
{ //"Cache Features" option; get all features in layer immediately |
|
102 |
reloadData(); |
|
103 |
} //otherwise, defer feature retrieval until layer is first rendered |
|
64 | 104 | |
65 | 105 |
if ( mValid ) |
66 | 106 |
{ |
... | ... | |
231 | 271 |
mAttributesToFetch = fetchAttributes; |
232 | 272 |
mFetchGeom = fetchGeometry; |
233 | 273 | |
234 |
QString dsURI = dataSourceUri(); |
|
235 |
if ( dsURI.contains( "BBOX" ) ) |
|
236 |
{ |
|
237 |
QUrl url( dsURI ); |
|
238 |
url.removeQueryItem( "BBOX" ); |
|
239 |
url.addQueryItem( "BBOX", QString::number( rect.xMinimum() ) + "," + QString::number( rect.yMinimum() ) + "," |
|
240 |
+ QString::number( rect.xMaximum() ) + "," + QString::number( rect.yMaximum() ) ); |
|
241 |
setDataSourceUri( url.toString() ); |
|
242 |
reloadData(); |
|
274 |
if ( rect.isEmpty() ) |
|
275 |
{ //select all features |
|
276 |
mSpatialFilter = mExtent; |
|
243 | 277 |
mSelectedFeatures = mFeatures.keys(); |
244 |
mSpatialFilter = rect; |
|
245 | 278 |
} |
246 | 279 |
else |
247 |
{ |
|
248 |
if ( rect.isEmpty() ) |
|
249 |
{ |
|
250 |
mSpatialFilter = mExtent; |
|
251 |
mSelectedFeatures = mFeatures.keys(); |
|
252 |
} |
|
253 |
else |
|
254 |
{ |
|
255 |
mSpatialFilter = rect; |
|
256 |
mSelectedFeatures = mSpatialIndex->intersects( mSpatialFilter ); |
|
280 |
{ //select features intersecting caller's extent |
|
281 |
QString dsURI = dataSourceUri(); |
|
282 |
//first time through, initialize GetRenderedOnly args |
|
283 |
//ctor cannot initialize because layer object not available then |
|
284 |
if ( ! mInitGro ) |
|
285 |
{ //did user check "Cache Features" in WFS layer source selection? |
|
286 |
if ( dsURI.contains( "BBOX" ) ) |
|
287 |
{ //no: initialize incremental getFeature |
|
288 |
if ( initGetRenderedOnly( rect ) ) |
|
289 |
{ |
|
290 |
mGetRenderedOnly = true; |
|
291 |
} |
|
292 |
else |
|
293 |
{ //initialization failed; |
|
294 |
QgsDebugMsg( QString( "GetRenderedOnly initialization failed; incorrect operation may occur\n%1" ) |
|
295 |
.arg( dataSourceUri() ) ); |
|
296 |
QMessageBox( QMessageBox::Warning, "Non-Cached layer initialization failed!", |
|
297 |
QString( "Incorrect operation may occur:\n%1" ).arg( dataSourceUri() ) ); |
|
298 |
} |
|
299 |
} |
|
300 |
mInitGro = true; |
|
301 |
} |
|
302 | ||
303 |
if ( mGetRenderedOnly ) |
|
304 |
{ //"Cache Features" was not selected for this layer |
|
305 |
//has rendered extent expanded beyond last-retrieved WFS extent? |
|
306 |
//NB: "intersect" instead of "contains" tolerates rounding errors; |
|
307 |
// avoids unnecessary second fetch on zoom-in/zoom-out sequences |
|
308 |
QgsRectangle olap( rect ); |
|
309 |
olap = olap.intersect( &mGetExtent ); |
|
310 |
if ( doubleNear( rect.width(), olap.width() ) && doubleNear ( rect.height(), olap.height() ) ) |
|
311 |
{ //difference between canvas and layer extents is within rounding error: do not re-fetch |
|
312 |
QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: no fetch required" ).arg( mLayer->name() ) ); |
|
313 |
} |
|
314 |
else |
|
315 |
{ //combined old and new extents might speed up local panning & zooming |
|
316 |
mGetExtent.combineExtentWith( &rect ); |
|
317 |
//but see if the combination is useless or too big |
|
318 |
double pArea = mGetExtent.width() * mGetExtent.height(); |
|
319 |
double cArea = rect.width() * rect.height(); |
|
320 |
if ( olap.isEmpty() || pArea > ( cArea * 4.0 ) ) |
|
321 |
{ //new canvas extent does not overlap or combining old and new extents would |
|
322 |
//fetch > 4 times the area to be rendered; get only what will be rendered |
|
323 |
mGetExtent = rect; |
|
324 |
} |
|
325 |
QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: fetching extent %2" ) |
|
326 |
.arg( mLayer->name(), mGetExtent.asWktCoordinates() ) ); |
|
327 |
dsURI = dsURI.replace( QRegExp( "BBOX=[^&]*" ), |
|
328 |
QString( "BBOX=%1,%2,%3,%4" ) |
|
329 |
.arg( mGetExtent.xMinimum(), 0, 'f' ) |
|
330 |
.arg( mGetExtent.yMinimum(), 0, 'f' ) |
|
331 |
.arg( mGetExtent.xMaximum(), 0, 'f' ) |
|
332 |
.arg( mGetExtent.yMaximum(), 0, 'f' ) ); |
|
333 |
//TODO: BBOX may not be combined with FILTER. WFS spec v. 1.1.0, sec. 14.7.3 ff. |
|
334 |
// if a FILTER is present, the BBOX must be merged into it, capabilities permitting. |
|
335 |
// Else one criterion must be abandoned and the user warned. [WBC 111221] |
|
336 |
setDataSourceUri( dsURI ); |
|
337 |
reloadData(); |
|
338 |
mLayer->updateExtents(); |
|
339 |
} |
|
257 | 340 |
} |
341 | ||
342 |
mSpatialFilter = rect; |
|
343 |
mSelectedFeatures = mSpatialIndex->intersects( mSpatialFilter ); |
|
258 | 344 |
} |
259 | 345 | |
260 | 346 |
mFeatureIterator = mSelectedFeatures.begin(); |
... | ... | |
262 | 348 | |
263 | 349 |
int QgsWFSProvider::getFeature( const QString& uri ) |
264 | 350 |
{ |
265 |
QString geometryAttribute; |
|
266 | ||
267 |
//Local url or HTTP? |
|
268 |
if ( uri.startsWith( "http" ) ) |
|
269 |
{ |
|
270 |
mEncoding = QgsWFSProvider::GET; |
|
271 |
} |
|
272 |
else |
|
273 |
{ |
|
274 |
mEncoding = QgsWFSProvider::FILE; |
|
275 |
} |
|
276 | ||
277 |
if ( mEncoding == QgsWFSProvider::FILE ) |
|
278 |
{ |
|
279 |
//guess geometry attribute and other attributes from schema or from .gml file |
|
280 |
if ( describeFeatureTypeFile( uri, mGeometryAttribute, mFields ) != 0 ) |
|
281 |
{ |
|
282 |
return 1; |
|
283 |
} |
|
284 |
} |
|
285 |
else //take schema with describeFeatureType request |
|
286 |
{ |
|
287 |
QString describeFeatureUri = uri; |
|
288 |
describeFeatureUri.replace( QString( "GetFeature" ), QString( "DescribeFeatureType" ) ); |
|
289 |
if ( describeFeatureType( describeFeatureUri, mGeometryAttribute, mFields ) != 0 ) |
|
290 |
{ |
|
291 |
return 1; |
|
292 |
} |
|
293 |
} |
|
294 | ||
295 | 351 |
if ( mEncoding == QgsWFSProvider::GET ) |
296 | 352 |
{ |
297 | 353 |
return getFeatureGET( uri, mGeometryAttribute ); |
298 | 354 |
} |
299 |
else//local file |
|
355 |
else //local file
|
|
300 | 356 |
{ |
301 | 357 |
return getFeatureFILE( uri, mGeometryAttribute ); //read the features from disk |
302 | 358 |
} |
... | ... | |
658 | 714 |
} |
659 | 715 |
} |
660 | 716 | |
661 |
int QgsWFSProvider::describeFeatureType( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields ) |
|
717 |
int QgsWFSProvider::describeFeatureType( const QString& uri, QString& geometryAttribute, |
|
718 |
QgsFieldMap& fields, QGis::WkbType& geomType ) |
|
719 |
//NB: also called from QgsWFSSourceSelect::on_treeWidget_itemDoubleClicked() to build filters. |
|
720 |
// a temporary provider object is constructed with a null URI, which bypasses much provider |
|
721 |
// instantiation logic: refresh(), getFeature(), etc. therefore, many provider class members |
|
722 |
// are only default values or uninitialized when running under the source select dialog! |
|
662 | 723 |
{ |
663 | 724 |
fields.clear(); |
664 |
switch ( mEncoding ) |
|
665 |
{ |
|
666 |
case QgsWFSProvider::GET: |
|
667 |
return describeFeatureTypeGET( uri, geometryAttribute, fields ); |
|
668 |
case QgsWFSProvider::FILE: |
|
669 |
return describeFeatureTypeFile( uri, geometryAttribute, fields ); |
|
670 |
} |
|
725 |
//Local url or HTTP? WBC111221 refactored here from getFeature() |
|
726 |
switch( mEncoding ) |
|
727 |
{ |
|
728 |
case QgsWFSProvider::GET: |
|
729 |
{ |
|
730 |
return describeFeatureTypeGET( uri, geometryAttribute, fields, geomType ); |
|
731 |
} |
|
732 |
case QgsWFSProvider::FILE: |
|
733 |
{ |
|
734 |
return describeFeatureTypeFile( uri, geometryAttribute, fields, geomType ); |
|
735 |
} |
|
736 |
} |
|
737 |
QgsDebugMsg( "SHOULD NOT OCCUR: mEncoding undefined" ); |
|
671 | 738 |
return 1; |
672 | 739 |
} |
673 | 740 | |
... | ... | |
682 | 749 |
thematicAttributes.insert( it.value().name(), qMakePair( it.key(), it.value() ) ); |
683 | 750 |
} |
684 | 751 | |
685 |
//create mSourceCRS from url if possible |
|
686 |
QString srsname = parameterFromUrl( "SRSNAME" ); |
|
687 |
if ( !srsname.isEmpty() ) |
|
688 |
{ |
|
689 |
mSourceCRS.createFromOgcWmsCrs( srsname ); |
|
690 |
} |
|
691 | ||
692 | 752 |
QgsWFSData dataReader( uri, &mExtent, mFeatures, mIdMap, geometryAttribute, thematicAttributes, &mWKBType ); |
693 | 753 |
QObject::connect( &dataReader, SIGNAL( dataProgressAndSteps( int , int ) ), this, SLOT( handleWFSProgressMessage( int, int ) ) ); |
694 | 754 | |
... | ... | |
765 | 825 |
return 0; |
766 | 826 |
} |
767 | 827 | |
768 |
int QgsWFSProvider::describeFeatureTypeGET( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields ) |
|
828 |
int QgsWFSProvider::describeFeatureTypeGET( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType )
|
|
769 | 829 |
{ |
770 | 830 |
if ( !mNetworkRequestFinished ) |
771 | 831 |
{ |
... | ... | |
774 | 834 | |
775 | 835 |
mNetworkRequestFinished = false; |
776 | 836 | |
777 |
QNetworkRequest request( uri ); |
|
837 |
QString describeFeatureUri = uri; |
|
838 |
describeFeatureUri.replace( QString( "GetFeature" ), QString( "DescribeFeatureType" ) ); |
|
839 |
QNetworkRequest request( describeFeatureUri ); |
|
778 | 840 |
QNetworkReply* reply = QgsNetworkAccessManager::instance()->get( request ); |
779 | 841 |
connect( reply, SIGNAL( finished() ), this, SLOT( networkRequestFinished() ) ); |
780 | 842 |
while ( !mNetworkRequestFinished ) |
... | ... | |
792 | 854 |
return 2; |
793 | 855 |
} |
794 | 856 | |
795 |
if ( readAttributesFromSchema( describeFeatureDocument, geometryAttribute, fields ) != 0 ) |
|
857 |
if ( readAttributesFromSchema( describeFeatureDocument, |
|
858 |
geometryAttribute, fields, geomType ) != 0 ) |
|
796 | 859 |
{ |
860 |
QgsDebugMsg( QString( "FAILED: readAttributesFromSchema" ) ); |
|
797 | 861 |
return 3; |
798 | 862 |
} |
799 | 863 | |
... | ... | |
805 | 869 |
mNetworkRequestFinished = true; |
806 | 870 |
} |
807 | 871 | |
808 |
int QgsWFSProvider::describeFeatureTypeFile( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields )
|
|
872 |
int QgsWFSProvider::describeFeatureTypeFile( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType)
|
|
809 | 873 |
{ |
810 | 874 |
//first look in the schema file |
811 | 875 |
QString noExtension = uri; |
... | ... | |
821 | 885 |
return 1; //xml file not readable or not valid |
822 | 886 |
} |
823 | 887 | |
824 |
if ( readAttributesFromSchema( schemaDoc, geometryAttribute, fields ) != 0 ) |
|
888 |
if ( readAttributesFromSchema( schemaDoc, geometryAttribute, fields, geomType ) != 0 )
|
|
825 | 889 |
{ |
826 | 890 |
return 2; |
827 | 891 |
} |
... | ... | |
846 | 910 |
return 0; |
847 | 911 |
} |
848 | 912 | |
849 |
int QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc, QString& geometryAttribute, QgsFieldMap& fields ) |
|
913 |
int QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType )
|
|
850 | 914 |
{ |
851 | 915 |
//get the <schema> root element |
852 | 916 |
QDomNodeList schemaNodeList = schemaDoc.elementsByTagNameNS( "http://www.w3.org/2001/XMLSchema", "schema" ); |
... | ... | |
921 | 985 | |
922 | 986 |
//is it a geometry attribute? |
923 | 987 |
//MH 090428: sometimes the <element> tags for geometry attributes have only attribute ref="gml:polygonProperty" and no name |
924 |
if (( type.startsWith( "gml:" ) && type.endsWith( "PropertyType" ) ) || name.isEmpty() ) |
|
988 |
QRegExp gmlPT( "gml:(.*)PropertyType" ); |
|
989 |
if ( type.indexOf( gmlPT ) == 0 || name.isEmpty() ) |
|
925 | 990 |
{ |
926 | 991 |
geometryAttribute = name; |
992 |
geomType = geomTypeFromPropertyType(geometryAttribute, gmlPT.cap(1) ); |
|
927 | 993 |
} |
928 | 994 |
else //todo: distinguish between numerical and non-numerical types |
929 | 995 |
{ |
... | ... | |
2288 | 2354 |
} |
2289 | 2355 |
} |
2290 | 2356 | |
2357 |
//initialization for getRenderedOnly option |
|
2358 |
//(formerly "Only request features overlapping the current view extent") |
|
2359 |
bool QgsWFSProvider::initGetRenderedOnly( const QgsRectangle rect ) |
|
2360 |
{ //find our layer |
|
2361 |
QMap<QString, QgsMapLayer*> layers = QgsMapLayerRegistry::instance()->mapLayers(); |
|
2362 |
QMap<QString, QgsMapLayer*>::const_iterator layersIt = layers.begin(); |
|
2363 |
for ( ; layersIt != layers.end() ; ++layersIt ) |
|
2364 |
{ |
|
2365 |
if ( ( mLayer = dynamic_cast<QgsVectorLayer*>( layersIt.value() ) ) ) |
|
2366 |
{ |
|
2367 |
if ( mLayer->dataProvider() == this ) |
|
2368 |
{ |
|
2369 |
QgsDebugMsg( QString( "found layer %1" ).arg( mLayer->name() ) ); |
|
2370 |
break; |
|
2371 |
} |
|
2372 |
} |
|
2373 |
} |
|
2374 |
if ( layersIt == layers.end() ) |
|
2375 |
{ |
|
2376 |
QgsDebugMsg( "SHOULD NOT OCCUR: initialize() did not find layer." ); |
|
2377 |
return false; |
|
2378 |
} |
|
2379 |
return true; |
|
2380 |
} |
|
2381 | ||
2382 |
QGis::WkbType QgsWFSProvider::geomTypeFromPropertyType( QString attName, QString propType ) |
|
2383 |
{ |
|
2384 |
const QStringList geomTypes = ( QStringList () |
|
2385 |
//all GML v.2.1.3 _geometryProperty group members, except MultiGeometryPropertyType |
|
2386 |
//sequence must exactly match enum Qgis::WkbType |
|
2387 |
<< "" // unknown geometry, enum 0 |
|
2388 |
<< "Point" |
|
2389 |
<< "LineString" |
|
2390 |
<< "Polygon" |
|
2391 |
<< "MultiPoint" |
|
2392 |
<< "MultiLineString" |
|
2393 |
<< "MultiPolygon" ); |
|
2394 | ||
2395 |
QgsDebugMsg( QString( "DescribeFeatureType geometry attribute \"%1\" type is \"%2\"" ) |
|
2396 |
.arg( attName, propType ) ); |
|
2397 |
int i = geomTypes.indexOf( propType ); |
|
2398 |
if ( i <= 0 ) |
|
2399 |
{ // feature type missing or unknown |
|
2400 |
i = (int) QGis::WKBUnknown; |
|
2401 |
} |
|
2402 |
return (QGis::WkbType) i; |
|
2403 |
} |
|
2404 | ||
2291 | 2405 |
void QgsWFSProvider::handleException( const QDomDocument& serverResponse ) const |
2292 | 2406 |
{ |
2293 | 2407 |
QDomElement exceptionElem = serverResponse.documentElement(); |
src/providers/wfs/qgswfsprovider.h | ||
---|---|---|
23 | 23 |
#include "qgsrectangle.h" |
24 | 24 |
#include "qgscoordinatereferencesystem.h" |
25 | 25 |
#include "qgsvectordataprovider.h" |
26 |
#include "qgsmaplayer.h" |
|
27 |
#include "qgsvectorlayer.h" |
|
26 | 28 | |
27 | 29 |
class QgsRectangle; |
28 | 30 |
class QgsSpatialIndex; |
... | ... | |
140 | 142 |
synchronize with changes in the data source*/ |
141 | 143 |
virtual void reloadData(); |
142 | 144 | |
143 |
/**Collects information about the field types. Is called internally from QgsWFSProvider::getFeature. 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*/ |
|
144 |
int describeFeatureType( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields ); |
|
145 |
/**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*/ |
|
146 |
int describeFeatureType( const QString& uri, QString& geometryAttribute, |
|
147 |
QgsFieldMap& fields, QGis::WkbType& geomType ); |
|
145 | 148 | |
146 | 149 |
signals: |
147 | 150 |
void dataReadProgressMessage( QString message ); |
... | ... | |
191 | 194 |
QString mWfsNamespace; |
192 | 195 |
/**Server capabilities for this layer (generated from capabilities document)*/ |
193 | 196 |
int mCapabilities; |
197 |
/**GetRenderedOnly: layer asociated with this provider*/ |
|
198 |
QgsVectorLayer *mLayer; |
|
199 |
/**GetRenderedOnly: fetch only features within canvas extent to be rendered*/ |
|
200 |
bool mGetRenderedOnly; |
|
201 |
/**GetRenderedOnly initializaiton flat*/ |
|
202 |
bool mInitGro; |
|
203 |
/**if GetRenderedOnly, extent specified in WFS getFeatures; else empty (no constraint)*/ |
|
204 |
QgsRectangle mGetExtent; |
|
194 | 205 | |
195 | 206 |
//encoding specific methods of getFeature |
196 | 207 |
int getFeatureGET( const QString& uri, const QString& geometryAttribute ); |
... | ... | |
198 | 209 |
int getFeatureSOAP( const QString& uri, const QString& geometryAttribute ); |
199 | 210 |
int getFeatureFILE( const QString& uri, const QString& geometryAttribute ); |
200 | 211 |
//encoding specific methods of describeFeatureType |
201 |
int describeFeatureTypeGET( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields ); |
|
212 |
int describeFeatureTypeGET( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType );
|
|
202 | 213 |
int describeFeatureTypePOST( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields ); |
203 | 214 |
int describeFeatureTypeSOAP( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields ); |
204 |
int describeFeatureTypeFile( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields ); |
|
215 |
int describeFeatureTypeFile( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType );
|
|
205 | 216 | |
206 | 217 |
/**Reads the name of the geometry attribute, the thematic attributes and their types from a dom document. Returns 0 in case of success*/ |
207 |
int readAttributesFromSchema( QDomDocument& schemaDoc, QString& geometryAttribute, QgsFieldMap& fields ); |
|
218 |
int readAttributesFromSchema( QDomDocument& schemaDoc, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType );
|
|
208 | 219 |
/**This method tries to guess the geometry attribute and the other attribute names from the .gml file if no schema is present. Returns 0 in case of success*/ |
209 | 220 |
int guessAttributesFromFile( const QString& uri, QString& geometryAttribute, std::list<QString>& thematicAttributes ) const; |
210 | 221 | |
... | ... | |
284 | 295 |
void appendSupportedOperations( const QDomElement& operationsElem, int& capabilities ) const; |
285 | 296 |
/**Shows a message box with the exception string (or does nothing if the xml document is not an exception)*/ |
286 | 297 |
void handleException( const QDomDocument& serverResponse ) const; |
298 |
/**Initializes "Cache Features" inactive processing*/ |
|
299 |
bool initGetRenderedOnly( QgsRectangle ); |
|
300 |
/**Converts DescribeFeatureType schema geometry property type to WKBType*/ |
|
301 |
QGis::WkbType geomTypeFromPropertyType( QString attName, QString propType ); |
|
287 | 302 | |
288 | 303 |
void deleteData(); |
289 | 304 |
}; |
src/providers/wfs/qgswfssourceselect.cpp | ||
---|---|---|
15 | 15 |
* * |
16 | 16 |
***************************************************************************/ |
17 | 17 | |
18 |
#include "qgisinterface.h" |
|
19 | 18 |
#include "qgswfssourceselect.h" |
20 | 19 |
#include "qgswfsconnection.h" |
21 | 20 |
#include "qgswfsprovider.h" |
... | ... | |
25 | 24 |
#include "qgscontexthelp.h" |
26 | 25 |
#include "qgsproject.h" |
27 | 26 |
#include "qgscoordinatereferencesystem.h" |
27 |
#include "qgscoordinatetransform.h" |
|
28 | 28 |
#include "qgslogger.h" |
29 | 29 |
#include "qgsmapcanvas.h" //for current view extent |
30 | 30 |
#include "qgsmanageconnectionsdialog.h" |
... | ... | |
263 | 263 | |
264 | 264 |
QList<QTreeWidgetItem*> selectedItems = treeWidget->selectedItems(); |
265 | 265 |
QList<QTreeWidgetItem*>::const_iterator sIt = selectedItems.constBegin(); |
266 |
for ( ; sIt != selectedItems.constEnd(); ++sIt ) |
|
266 |
QgsWFSConnection conn( cmbConnections->currentText() ); |
|
267 |
QString pCrsString( labelCoordRefSys->text() ); |
|
268 |
QgsCoordinateReferenceSystem pCrs( pCrsString ); |
|
269 |
//prepare canvas extent info for layers with "cache features" option not set |
|
270 |
QgsRectangle extent; |
|
271 |
QVariant extentVariant = property( "MapExtent" ); |
|
272 |
if ( extentVariant.isValid() ) |
|
267 | 273 |
{ |
268 |
QString typeName = ( *sIt )->text( 1 ); |
|
269 |
QString crs = labelCoordRefSys->text(); |
|
270 |
QString filter = ( *sIt )->text( 4 ); |
|
271 | ||
272 |
QgsRectangle currentRectangle; |
|
273 |
if (( *sIt )->checkState( 3 ) == Qt::Unchecked ) |
|
274 |
QString crs; |
|
275 |
QgsCoordinateTransform xform; |
|
276 |
QString extentString = extentVariant.toString(); |
|
277 |
QStringList minMaxSplit = extentString.split( ":" ); |
|
278 |
if ( minMaxSplit.size() > 1 ) |
|
274 | 279 |
{ |
275 |
currentRectangle = mExtent; |
|
280 |
QStringList xyMinSplit = minMaxSplit[0].split( "," ); |
|
281 |
QStringList xyMaxSplit = minMaxSplit[1].split( "," ); |
|
282 |
if ( xyMinSplit.size() > 1 && xyMaxSplit.size() > 1 ) |
|
283 |
{ |
|
284 |
extent.set( xyMinSplit[0].toDouble(), xyMinSplit[1].toDouble(), |
|
285 |
xyMaxSplit[0].toDouble(), xyMaxSplit[1].toDouble() ); |
|
286 |
} |
|
287 |
} |
|
288 |
//does canvas have "on the fly" reprojection set? |
|
289 |
QVariant crsVariant = property( "MapCRS" ); |
|
290 |
if ( crsVariant.isValid() ) |
|
291 |
{ //transform between provider CRS set in source select dialog and canvas CRS |
|
292 |
QgsCoordinateReferenceSystem cCrs( crsVariant.toString() ); |
|
293 |
if ( pCrs.isValid() && cCrs.isValid() ) |
|
294 |
{ |
|
295 |
QgsCoordinateTransform xform( pCrs, cCrs ); |
|
296 |
extent = xform.transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform ); |
|
297 |
QgsDebugMsg( QString("canvas transform: Canvas CRS=%1, Provider CRS=%2, BBOX=%3") |
|
298 |
.arg(cCrs.authid(), pCrs.authid(), extent.asWktCoordinates() ) ); |
|
299 |
} |
|
276 | 300 |
} |
277 | ||
278 |
//add a wfs layer to the map |
|
279 |
QgsWFSConnection conn( cmbConnections->currentText() ); |
|
280 |
QString uri = conn.uriGetFeature( typeName, crs, filter, currentRectangle ); |
|
281 |
emit addWfsLayer( uri, typeName ); |
|
301 |
} |
|
302 |
//create layers that user selected from this WFS source |
|
303 |
for ( ; sIt != selectedItems.constEnd(); ++sIt ) |
|
304 |
{ //add a wfs layer to the map |
|
305 |
QString typeName = ( *sIt )->text( 1 ); //WFS repository's name for layer |
|
306 |
QString filter = ( *sIt )->text( 4 ); //optional filter specified by user |
|
307 |
//is "cache features" checked? |
|
308 |
if ( ( *sIt )->checkState( 3 ) == Qt::Checked ) |
|
309 |
{ //yes: entire WFS layer will be retrieved and cached |
|
310 |
mUri = conn.uriGetFeature( typeName, pCrsString, filter ); |
|
311 |
} |
|
312 |
else |
|
313 |
{ //no: include BBOX of current canvas extent in URI |
|
314 |
mUri = conn.uriGetFeature( typeName, pCrsString, filter, extent ); |
|
315 |
} |
|
316 |
emit addWfsLayer( mUri, typeName ); |
|
282 | 317 |
} |
283 | 318 |
accept(); |
284 | 319 |
} |
... | ... | |
365 | 400 |
if ( item && column == 4 ) |
366 | 401 |
{ |
367 | 402 |
//get available fields for wfs layer |
368 |
QgsWFSProvider p( "" ); |
|
403 |
QgsWFSProvider p( "" ); //bypasses most provider instantiation logic
|
|
369 | 404 |
QgsWFSConnection conn( cmbConnections->currentText() ); |
370 | 405 |
QString uri = conn.uriDescribeFeatureType( item->text( 1 ) ); |
371 | 406 | |
372 | 407 |
QgsFieldMap fields; |
373 | 408 |
QString geometryAttribute; |
374 |
if ( p.describeFeatureType( uri, geometryAttribute, fields ) != 0 ) |
|
409 |
QGis::WkbType geomType; |
|
410 |
if ( p.describeFeatureType( uri, geometryAttribute, fields, geomType ) != 0 ) |
|
375 | 411 |
{ |
376 | 412 |
return; |
377 | 413 |
} |
378 | 414 | |
379 | ||
380 | 415 |
//show expression builder |
381 | 416 |
QgsExpressionBuilderDialog d( 0, item->text( 3 ) ); |
382 | 417 | |
... | ... | |
399 | 434 |
} |
400 | 435 |
} |
401 | 436 |
} |
402 | ||
403 |
void QgsWFSSourceSelect::showEvent( QShowEvent* event ) |
|
404 |
{ |
|
405 |
Q_UNUSED( event ); |
|
406 |
QVariant extentVariant = property( "MapExtent" ); |
|
407 |
if ( extentVariant.isValid() ) |
|
408 |
{ |
|
409 |
QString extentString = extentVariant.toString(); |
|
410 |
QStringList minMaxSplit = extentString.split( ":" ); |
|
411 |
if ( minMaxSplit.size() > 1 ) |
|
412 |
{ |
|
413 |
QStringList xyMinSplit = minMaxSplit[0].split( "," ); |
|
414 |
QStringList xyMaxSplit = minMaxSplit[1].split( "," ); |
|
415 |
if ( xyMinSplit.size() > 1 && xyMaxSplit.size() > 1 ) |
|
416 |
{ |
|
417 |
mExtent.set( xyMinSplit[0].toDouble(), xyMinSplit[1].toDouble(), xyMaxSplit[0].toDouble(), xyMaxSplit[1].toDouble() ); |
|
418 |
return; |
|
419 |
} |
|
420 |
} |
|
421 |
} |
|
422 |
} |
src/providers/wfs/qgswfssourceselect.h | ||
---|---|---|
20 | 20 | |
21 | 21 |
#include "ui_qgswfssourceselectbase.h" |
22 | 22 |
#include "qgscontexthelp.h" |
23 |
#include "qgsrectangle.h" |
|
24 | 23 | |
25 | 24 |
class QgsGenericProjectionSelector; |
26 | 25 |
class QgsWFSConnection; |
... | ... | |
47 | 46 |
std::map<QString, std::list<QString> > mAvailableCRS; |
48 | 47 |
QAbstractButton* btnAdd; |
49 | 48 |
QgsWFSConnection* mConn; |
50 |
QgsRectangle mExtent;
|
|
49 |
QString mUri; // data source URI
|
|
51 | 50 | |
52 | 51 |
void populateConnectionList(); |
53 | 52 | |
... | ... | |
74 | 73 | |
75 | 74 |
void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); } |
76 | 75 | |
77 |
protected: |
|
78 |
void showEvent( QShowEvent* event ); |
|
79 | 76 |
}; |
80 | 77 | |
81 | 78 |
#endif |
src/ui/qgswfssourceselectbase.ui | ||
---|---|---|
6 | 6 |
<rect> |
7 | 7 |
<x>0</x> |
8 | 8 |
<y>0</y> |
9 |
<width>552</width>
|
|
9 |
<width>592</width>
|
|
10 | 10 |
<height>439</height> |
11 | 11 |
</rect> |
12 | 12 |
</property> |
... | ... | |
114 | 114 |
<property name="columnCount"> |
115 | 115 |
<number>5</number> |
116 | 116 |
</property> |
117 |
<attribute name="headerMinimumSectionSize"> |
|
118 |
<number>27</number> |
|
119 |
</attribute> |
|
120 |
<attribute name="headerMinimumSectionSize"> |
|
121 |
<number>27</number> |
|
122 |
</attribute> |
|
117 | 123 |
<column> |
118 | 124 |
<property name="text"> |
119 | 125 |
<string>Title</string> |
... | ... | |
131 | 137 |
</column> |
132 | 138 |
<column> |
133 | 139 |
<property name="text"> |
134 |
<string>cache features</string> |
|
140 |
<string>Cache |
|
141 |
Features</string> |
|
142 |
</property> |
|
143 |
<property name="textAlignment"> |
|
144 |
<set>AlignHCenter|AlignVCenter|AlignCenter</set> |
|
135 | 145 |
</property> |
136 | 146 |
</column> |
137 | 147 |
<column> |