incremental-wsf-rev2.patch

WFS incremental fetch patch; replaces prior version - Bill Clay, 2011-12-22 07:03 AM

Download (28.4 KB)

View differences:

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>