1 /*************************************************************************** 2 qgswfsshareddata.h 3 --------------------- 4 begin : March 2016 5 copyright : (C) 2016 by Even Rouault 6 email : even.rouault at spatialys.com 7 *************************************************************************** 8 * * 9 * This program is free software; you can redistribute it and/or modify * 10 * it under the terms of the GNU General Public License as published by * 11 * the Free Software Foundation; either version 2 of the License, or * 12 * (at your option) any later version. * 13 * * 14 ***************************************************************************/ 15 #ifndef QGSWFSSHAREDDATA_H 16 #define QGSWFSSHAREDDATA_H 17 18 #include "qgswfsfeatureiterator.h" 19 #include "qgswfsrequest.h" 20 #include "qgswfscapabilities.h" 21 #include "qgsogcutils.h" 22 23 #include "qgsbackgroundcachedshareddata.h" 24 #include "qgsbackgroundcachedfeatureiterator.h" 25 26 //! Class shared between provider and feature source 27 class QgsWFSSharedData : public QObject, public QgsBackgroundCachedSharedData 28 { 29 Q_OBJECT 30 public: 31 explicit QgsWFSSharedData( const QString &uri ); 32 ~QgsWFSSharedData() override; 33 34 //! Compute WFS filter from the sql or filter in the URI 35 bool computeFilter( QString &errorMsg ); 36 37 //! Returns srsName 38 QString srsName() const; 39 40 //! Return provider geometry attribute name geometryAttribute()41 const QString &geometryAttribute() const { return mGeometryAttribute; } 42 43 std::unique_ptr<QgsFeatureDownloaderImpl> newFeatureDownloaderImpl( QgsFeatureDownloader *, bool requestFromMainThread ) override; 44 45 bool isRestrictedToRequestBBOX() const override; 46 hasGeometry()47 bool hasGeometry() const override { return !mGeometryAttribute.isEmpty(); } 48 49 //! Set a new filter and return the previous one. Only used to temporarily disable filtering when trying to get layer geometry type. setWFSFilter(const QString & newFilter)50 QString setWFSFilter( const QString &newFilter ) { QString oldFilter = mWFSFilter; mWFSFilter = newFilter; return oldFilter; } 51 52 signals: 53 54 //! Raise error 55 void raiseError( const QString &errorMsg ) const; 56 57 //! Extent has been updated 58 void extentUpdated(); 59 60 protected: 61 friend class QgsWFSFeatureDownloaderImpl; 62 friend class QgsWFSProvider; 63 friend class QgsWFSSingleFeatureRequest; 64 65 //! Datasource URI 66 QgsWFSDataSourceURI mURI; 67 68 //! WFS version to use. Comes from GetCapabilities response 69 QString mWFSVersion; 70 71 //! Name of geometry attribute 72 QString mGeometryAttribute; 73 74 //! Layer properties 75 QList< QgsOgcUtils::LayerProperties > mLayerPropertiesList; 76 77 //! Map a field name to the pair (typename, fieldname) that describes its source field 78 QMap< QString, QPair<QString, QString> > mMapFieldNameToSrcLayerNameFieldName; 79 80 //! Page size for WFS 2.0. 0 = disabled 81 int mPageSize = 0; 82 83 //! Server capabilities 84 QgsWfsCapabilities::Capabilities mCaps; 85 86 //! If we have already issued a warning about missing feature ids 87 bool mHasWarnedAboutMissingFeatureId = false; 88 89 /** 90 * If the server (typically MapServer WFS 1.1) honours EPSG axis order, but returns 91 * EPSG:XXXX srsName and not EPSG urns 92 */ 93 bool mGetFeatureEPSGDotHonoursEPSGOrder = false; 94 95 /** 96 * If the server (typically ESRI with WFS-T 1.1 in 2020) does not like "pos" and "posList", and requires "coordinates" for WFS 1.1 transactions 97 */ 98 bool mServerPrefersCoordinatesForTransactions_1_1 = false; 99 100 //! Geometry type of the features in this layer 101 QgsWkbTypes::Type mWKBType = QgsWkbTypes::Unknown; 102 103 //! Create GML parser 104 QgsGmlStreamingParser *createParser() const; 105 106 //! Returns true if it is likely that the server doesn't properly honor axis order. 107 bool detectPotentialServerAxisOrderIssueFromSingleFeatureExtent() const override; 108 109 private: 110 111 //! WFS filter 112 QString mWFSFilter; 113 114 //! WFS SORTBY 115 QString mSortBy; 116 117 //! Log error to QgsMessageLog and raise it to the provider 118 void pushError( const QString &errorMsg ) const override; 119 emitExtentUpdated()120 void emitExtentUpdated() override { emit extentUpdated(); } 121 122 void invalidateCacheBaseUnderLock() override; 123 supportsLimitedFeatureCountDownloads()124 bool supportsLimitedFeatureCountDownloads() const override { return !( mWFSVersion.startsWith( QLatin1String( "1.0" ) ) ); } 125 layerName()126 QString layerName() const override { return mURI.typeName(); } 127 hasServerSideFilter()128 bool hasServerSideFilter() const override { return !mWFSFilter.isEmpty(); } 129 supportsFastFeatureCount()130 bool supportsFastFeatureCount() const override { return mCaps.supportsHits; } 131 132 QgsRectangle getExtentFromSingleFeatureRequest() const override; 133 134 int getFeatureCountFromServer() const override; 135 }; 136 137 //! Utility class to issue a GetFeature resultType=hits request 138 class QgsWFSFeatureHitsRequest: public QgsWfsRequest 139 { 140 Q_OBJECT 141 public: 142 explicit QgsWFSFeatureHitsRequest( const QgsWFSDataSourceURI &uri ); 143 144 //! Returns the feature count, or -1 in case of error 145 int getFeatureCount( const QString &WFSVersion, const QString &filter, const QgsWfsCapabilities::Capabilities &caps ); 146 147 protected: 148 QString errorMessageWithReason( const QString &reason ) override; 149 }; 150 151 /** 152 * Utility class to issue a GetFeature requets with maxfeatures/count=1 153 * Used by QgsWFSSharedData::endOfDownload() when capabilities extent are likely wrong 154 */ 155 class QgsWFSSingleFeatureRequest: public QgsWfsRequest 156 { 157 Q_OBJECT 158 public: 159 explicit QgsWFSSingleFeatureRequest( const QgsWFSSharedData *shared ); 160 161 //! Returns the feature extent of the single feature requested 162 QgsRectangle getExtent(); 163 164 protected: 165 QString errorMessageWithReason( const QString &reason ) override; 166 167 private: 168 const QgsWFSSharedData *mShared = nullptr; 169 }; 170 171 #endif // QGSWFSSHAREDDATA_H 172