diff --git a/src/gui/qgsexpressionbuilderwidget.cpp b/src/gui/qgsexpressionbuilderwidget.cpp
index 2686031..dc5f4da 100644
--- a/src/gui/qgsexpressionbuilderwidget.cpp
+++ b/src/gui/qgsexpressionbuilderwidget.cpp
@@ -281,6 +281,7 @@ void QgsExpressionBuilderWidget::on_txtExpressionString_textChanged()
   }
   else
   {
+    lblPreview->setText( tr( "Expression is valid" ) );
     lblPreview->setStyleSheet( "" );
     txtExpressionString->setToolTip( "" );
     lblPreview->setToolTip( "" );
diff --git a/src/providers/wfs/qgswfsconnection.cpp b/src/providers/wfs/qgswfsconnection.cpp
index d1b7087..2049a09 100644
--- a/src/providers/wfs/qgswfsconnection.cpp
+++ b/src/providers/wfs/qgswfsconnection.cpp
@@ -9,6 +9,7 @@
 #include <QStringList>
 
 static const QString WFS_NAMESPACE = "http://www.opengis.net/wfs";
+static const QString OGC_NAMESPACE = "http://www.opengis.net/ogc";
 
 QgsWFSConnection::QgsWFSConnection( QString connName, QObject *parent ) :
     QObject( parent ),
@@ -220,6 +221,10 @@ void QgsWFSConnection::capabilitiesReplyFinished()
     mCaps.featureTypes.append( featureType );
   }
 
+  // get filter capability
+  QDomNodeList fcap = capabilitiesDocument.elementsByTagNameNS( OGC_NAMESPACE, "Filter_Capabilities" );
+  mCaps.canFilter = ( fcap.size() && fcap.at( 0 ).hasChildNodes() );
+
   mCapabilitiesReply->deleteLater();
   mCapabilitiesReply = 0;
   emit gotCapabilities();
diff --git a/src/providers/wfs/qgswfsconnection.h b/src/providers/wfs/qgswfsconnection.h
index 07624de..fbb8f92 100644
--- a/src/providers/wfs/qgswfsconnection.h
+++ b/src/providers/wfs/qgswfsconnection.h
@@ -48,8 +48,9 @@ class QgsWFSConnection : public QObject
     //! parsed get capabilities document
     struct GetCapabilities
     {
-      void clear() { featureTypes.clear(); }
+      void clear() { featureTypes.clear(); canFilter = false; }
 
+      bool canFilter;  //provider advertises <Filter> capability
       QList<FeatureType> featureTypes;
     };
 
diff --git a/src/providers/wfs/qgswfsdata.cpp b/src/providers/wfs/qgswfsdata.cpp
index d334818..b48ff70 100644
--- a/src/providers/wfs/qgswfsdata.cpp
+++ b/src/providers/wfs/qgswfsdata.cpp
@@ -47,7 +47,7 @@ QgsWFSData::QgsWFSData(
     mThematicAttributes( thematicAttributes ),
     mWkbType( wkbType ),
     mFinished( false ),
-    mFeatureCount( 0 )
+    mFeatureCount( /*0 [wbc 111225 incremental get*/ mFeatures.count() )
 {
   //find out mTypeName from uri
   QStringList arguments = uri.split( "&" );
@@ -75,8 +75,13 @@ QgsWFSData::~QgsWFSData()
 
 }
 
-int QgsWFSData::getWFSData()
+int QgsWFSData::getWFSData( const QSet<QString>* wfsFids )
 {
+  QgsDebugMsg( QString( "begin fetch: %1 cached features; %2 discard candidates" )
+                        .arg( mFeatureCount ).arg( wfsFids ? wfsFids->size() : 0 ) );
+
+  mWfsFids = wfsFids;
+
   XML_Parser p = XML_ParserCreateNS( NULL, NS_SEPARATOR );
   XML_SetUserData( p, this );
   XML_SetElementHandler( p, QgsWFSData::start, QgsWFSData::end );
@@ -142,6 +147,8 @@ int QgsWFSData::getWFSData()
 
 void QgsWFSData::setFinished( )
 {
+  QgsDebugMsg( QString( "end fetch: %1 features in cache" )
+                        .arg( mFeatureCount ) );
   mFinished = true;
 }
 
@@ -301,29 +308,38 @@ void QgsWFSData::endElement( const XML_Char* el )
     }
   }
   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "featureMember" )
-  {
-    //MH090531: Check if all feature attributes are initialised, sometimes attribute values are missing.
-    //We fill the not initialized ones with empty strings, otherwise the feature cannot be exported to shp later
-    QgsAttributeMap currentFeatureAttributes = mCurrentFeature->attributeMap();
-    QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constBegin();
-    for ( ; att_it != mThematicAttributes.constEnd(); ++att_it )
+  { //ignore duplicate features (e.g., protrude beyond previous extent)
+    //[wbc111228 issue 4280: fetch un-cached features on demand]
+    if ( mWfsFids && ! mCurrentFeatureId.isEmpty() && mWfsFids->contains( mCurrentFeatureId ) )
+    {
+      QgsDebugMsg( QString( "WFS FID %1 already fetched QGIS id %2" )
+                            .arg( mCurrentFeatureId )
+                            .arg( mIdMap.key ( mCurrentFeatureId ) ) );
+    }
+    else
     {
-      int attIndex = att_it.value().first;
-      QgsAttributeMap::const_iterator findIt = currentFeatureAttributes.find( attIndex );
-      if ( findIt == currentFeatureAttributes.constEnd() )
+      //MH090531: Check if all feature attributes are initialised, sometimes attribute values are missing.
+      //We fill the not initialized ones with empty strings, otherwise the feature cannot be exported to shp later
+      QgsAttributeMap currentFeatureAttributes = mCurrentFeature->attributeMap();
+      QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constBegin();
+      for ( ; att_it != mThematicAttributes.constEnd(); ++att_it )
       {
-        mCurrentFeature->addAttribute( attIndex, QVariant( "" ) );
+        int attIndex = att_it.value().first;
+        QgsAttributeMap::const_iterator findIt = currentFeatureAttributes.find( attIndex );
+        if ( findIt == currentFeatureAttributes.constEnd() )
+        {
+          mCurrentFeature->addAttribute( attIndex, QVariant( "" ) );
+        }
       }
-    }
-
 
-    mCurrentFeature->setGeometryAndOwnership( mCurrentWKB, mCurrentWKBSize );
-    mFeatures.insert( mCurrentFeature->id(), mCurrentFeature );
-    if ( !mCurrentFeatureId.isEmpty() )
-    {
-      mIdMap.insert( mCurrentFeature->id(), mCurrentFeatureId );
+      mCurrentFeature->setGeometryAndOwnership( mCurrentWKB, mCurrentWKBSize );
+      mFeatures.insert( mCurrentFeature->id(), mCurrentFeature );
+      if ( !mCurrentFeatureId.isEmpty() )
+      {
+        mIdMap.insert( mCurrentFeature->id(), mCurrentFeatureId );
+      }
+      ++mFeatureCount;
     }
-    ++mFeatureCount;
     mParseModeStack.pop();
   }
   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Point" )
diff --git a/src/providers/wfs/qgswfsdata.h b/src/providers/wfs/qgswfsdata.h
index 5c37e0f..9c816fb 100644
--- a/src/providers/wfs/qgswfsdata.h
+++ b/src/providers/wfs/qgswfsdata.h
@@ -51,7 +51,7 @@ class QgsWFSData: public QObject
        @param srs the reference system of the layer
        @param features the features of the layer
     @return 0 in case of success*/
-    int getWFSData();
+    int getWFSData( const QSet<QString>* wfsFids = (QSet<QString>*) 0 );
 
   private slots:
     void setFinished();
@@ -175,6 +175,8 @@ class QgsWFSData: public QObject
     QString mCoordinateSeparator;
     /**Tuple separator for coordinate strings. Usually " " */
     QString mTupleSeparator;
+    /**incremental get: optional list of FIDs to be ignored in WFS input stream*/
+    const QSet<QString>* mWfsFids;
 };
 
 #endif
diff --git a/src/providers/wfs/qgswfsprovider.cpp b/src/providers/wfs/qgswfsprovider.cpp
index c8a73d0..d40375b 100644
--- a/src/providers/wfs/qgswfsprovider.cpp
+++ b/src/providers/wfs/qgswfsprovider.cpp
@@ -17,7 +17,6 @@
 
 #define WFS_THRESHOLD 200
 
-#include "qgis.h"
 #include "qgsapplication.h"
 #include "qgsmaplayerregistry.h"
 #include "qgsfeature.h"
@@ -49,6 +48,7 @@ static const QString GML_NAMESPACE = "http://www.opengis.net/gml";
 QgsWFSProvider::QgsWFSProvider( const QString& uri )
     : QgsVectorDataProvider( uri ),
     mNetworkRequestFinished( true ),
+    mGeometryAttribute( 0 ),
     mEncoding( QgsWFSProvider::GET ),
     mUseIntersect( false ),
     mWKBType( QGis::WKBUnknown ),
@@ -57,7 +57,10 @@ QgsWFSProvider::QgsWFSProvider( const QString& uri )
     mValid( true ),
     mLayer( 0 ),
     mGetRenderedOnly( false ),
-    mInitGro( false )
+    mInitUri(),
+    mGetExtent(),
+    mWfsFids( 0 ),
+    mFilterCaps( 0 )
 {
   mSpatialIndex = 0;
   if ( uri.isEmpty() )
@@ -66,7 +69,8 @@ QgsWFSProvider::QgsWFSProvider( const QString& uri )
     return;
   }
 
-  //Local url or HTTP?  [WBC 111221] refactored from getFeature()
+  //Local url or HTTP?  refactored from getFeature()
+  //[wbc111228 issue 4280: fetch un-cached features on demand]
   if ( uri.startsWith( "http" ) )
   {
     mEncoding = QgsWFSProvider::GET;
@@ -75,30 +79,46 @@ QgsWFSProvider::QgsWFSProvider( const QString& uri )
   {
     mEncoding = QgsWFSProvider::FILE;
   }
-
-  //create mSourceCRS from url if possible [WBC 111221] refactored from GetFeatureGET()
+  //create mSourceCRS from url if possible; refactored from GetFeatureGET()
   QString srsname = parameterFromUrl( "SRSNAME" );
   if ( !srsname.isEmpty() )
   {
     mSourceCRS.createFromOgcWmsCrs( srsname );
   }
-
   //fetch attributes of layer and type of its geometry attribute
-  //WBC 111221: extracting geometry type here instead of getFeature allows successful
+  //extracting geometry type before getFeature usually allows successful
   //layer creation even when no features are retrieved (due to, e.g., BBOX or FILTER)
-  if ( describeFeatureType( uri, mGeometryAttribute, mFields, mWKBType ) )
+  QString describeFeatureUri = uri;
+  describeFeatureUri.replace( QString( "GetFeature" ), QString( "DescribeFeatureType" ) );
+  if ( describeFeatureType( describeFeatureUri, mGeometryAttribute, mFields, mWKBType ) )
   {
-    mValid = false;
     QgsDebugMsg( QString( "describeFeatureType failed, URI=%1" ).arg( uri ) );
-    QMessageBox( QMessageBox::Warning, "DescribeFeatureType failed!",
-                 QString( "Layer cannot be created from\n%1" ).arg( uri ) );
+    QMessageBox::critical ( 0, tr( "DescribeFeatureType failed!" ),
+                 tr( "Layer cannot be created from\n%1" ).arg( uri ) );
+    mValid = false;
     return;
   }
-
-  if ( ! uri.contains( "BBOX" ) )
-  { //"Cache Features" option; get all features in layer immediately
+  //fetch features now or on first render?
+  if ( mEncoding == QgsWFSProvider::FILE || ! uri.contains("BBOX") || mWKBType == QGis::WKBUnknown )
+  { //now if (1) local URL, (2) "Cache All Features" option, or (3) WFS describeFeatureType does
+    //not disclose a specific geometry type (e.g., TinyOWS reports "GeometryPropertyType")
+    //retrieve all features in layer immediately
     reloadData();
-  } //otherwise, defer feature retrieval until layer is first rendered
+  } //otherwise: defer feature fetch until layer is first rendered
+  else
+  {
+    mSpatialIndex = new QgsSpatialIndex();
+  }
+  //if we still do not know geometry type, user needs to change source select parameters
+  if ( mWKBType == QGis::WKBUnknown )
+  {
+    QgsDebugMsg( QString( "Cannot obtain geometry type, URI=%1" ).arg( uri ) );
+    QMessageBox::critical ( 0, tr( "Cannot obtain geometry type!" ),
+                 tr( "This layer contains no geometry features in the current map canvas extent. "
+                 "Reposition the map or check \"Cache All Features\" in the layer selection dialog." ) );
+    mValid = false;
+  }
+  //[end mods for issue 4280]
 
   if ( mValid )
   {
@@ -118,6 +138,14 @@ void QgsWFSProvider::reloadData()
   delete mSpatialIndex;
   mSpatialIndex = new QgsSpatialIndex();
   mValid = !getFeature( dataSourceUri() );
+  if ( mValid )
+  { //record fetched extent per stand-alone BBOX (if any) in getFeature URI
+    mGetExtent = getUriBBox();
+  }
+  else
+  { //getFeature failed; clear getFeature fetch extent
+    mGetExtent = QgsRectangle();
+  }
 }
 
 void QgsWFSProvider::deleteData()
@@ -128,6 +156,8 @@ void QgsWFSProvider::deleteData()
     delete mFeatures[i];
   }
   mFeatures.clear();
+  mFeatureCount = 0;
+  mIdMap.clear();
 }
 
 void QgsWFSProvider::copyFeature( QgsFeature* f, QgsFeature& feature, bool fetchGeometry, QgsAttributeList fetchAttributes )
@@ -269,72 +299,31 @@ void QgsWFSProvider::select( QgsAttributeList fetchAttributes,
   mAttributesToFetch = fetchAttributes;
   mFetchGeom = fetchGeometry;
 
+  //first time through, initialize GetRenderedOnly logic
+  //(layer object not available during ctor initialization)
+  //[wbc111228 issue 4604: fetch rendered features only]
+  //[issue 4280: fetch un-cached features on demand]
+  if ( mEncoding == QgsWFSProvider::GET && mInitUri.isEmpty() )
+  { //did user check "Cache All Features" in WFS layer source selection?
+    if ( dataSourceUri().contains( "BBOX" ) )
+    { //no: initialize incremental getFeature
+      mGetRenderedOnly = initGetRenderedOnly( rect );
+    }
+    //getRenderedOnly manipulates dataSourceUri; save original URI
+    mInitUri = dataSourceUri();
+  }
+
   if ( rect.isEmpty() )
-  { //select all features
+  { //select all previously-retrieved features
     mSpatialFilter = mExtent;
     mSelectedFeatures = mFeatures.keys();
   }
   else
-  { //select features intersecting caller's extent
-    QString dsURI = dataSourceUri();
-    //first time through, initialize GetRenderedOnly args
-    //ctor cannot initialize because layer object not available then
-    if ( ! mInitGro )
-    { //did user check "Cache Features" in WFS layer source selection?
-      if ( dsURI.contains( "BBOX" ) )
-      { //no: initialize incremental getFeature
-        if ( initGetRenderedOnly( rect ) )
-        {
-          mGetRenderedOnly = true;
-        }
-        else
-        { //initialization failed;
-          QgsDebugMsg( QString( "GetRenderedOnly initialization failed; incorrect operation may occur\n%1" )
-                       .arg( dataSourceUri() ) );
-          QMessageBox( QMessageBox::Warning, "Non-Cached layer initialization failed!",
-                       QString( "Incorrect operation may occur:\n%1" ).arg( dataSourceUri() ) );
-        }
-      }
-      mInitGro = true;
-    }
-
+  { //select features intersecting caller's extent (e.g., map canvas extent)
     if ( mGetRenderedOnly )
-    { //"Cache Features" was not selected for this layer
-      //has rendered extent expanded beyond last-retrieved WFS extent?
-      //NB: "intersect" instead of "contains" tolerates rounding errors;
-      //    avoids unnecessary second fetch on zoom-in/zoom-out sequences
-      QgsRectangle olap( rect );
-      olap = olap.intersect( &mGetExtent );
-      if ( doubleNear( rect.width(), olap.width() ) && doubleNear( rect.height(), olap.height() ) )
-      { //difference between canvas and layer extents is within rounding error: do not re-fetch
-        QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: no fetch required" ).arg( mLayer->name() ) );
-      }
-      else
-      { //combined old and new extents might speed up local panning & zooming
-        mGetExtent.combineExtentWith( &rect );
-        //but see if the combination is useless or too big
-        double pArea = mGetExtent.width() * mGetExtent.height();
-        double cArea = rect.width() * rect.height();
-        if ( olap.isEmpty() || pArea > ( cArea * 4.0 ) )
-        { //new canvas extent does not overlap or combining old and new extents would
-          //fetch > 4 times the area to be rendered; get only what will be rendered
-          mGetExtent = rect;
-        }
-        QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: fetching extent %2" )
-                     .arg( mLayer->name(), mGetExtent.asWktCoordinates() ) );
-        dsURI = dsURI.replace( QRegExp( "BBOX=[^&]*" ),
-                               QString( "BBOX=%1,%2,%3,%4" )
-                               .arg( mGetExtent.xMinimum(), 0, 'f' )
-                               .arg( mGetExtent.yMinimum(), 0, 'f' )
-                               .arg( mGetExtent.xMaximum(), 0, 'f' )
-                               .arg( mGetExtent.yMaximum(), 0, 'f' ) );
-        //TODO: BBOX may not be combined with FILTER. WFS spec v. 1.1.0, sec. 14.7.3 ff.
-        //      if a FILTER is present, the BBOX must be merged into it, capabilities permitting.
-        //      Else one criterion must be abandoned and the user warned.  [WBC 111221]
-        setDataSourceUri( dsURI );
-        reloadData();
-        mLayer->updateExtents();
-      }
+    { //"Cache All Features" was not selected for this layer; fetch features to be rendered
+      //[issues 4604 + 4280]
+      incrementalGet( rect );
     }
 
     mSpatialFilter = rect;
@@ -713,24 +702,20 @@ bool QgsWFSProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
 }
 
 int QgsWFSProvider::describeFeatureType( const QString& uri, QString& geometryAttribute,
-    QgsFieldMap& fields, QGis::WkbType& geomType )
+                                         QgsFieldMap& fields, QGis::WkbType& geomType )
 //NB: also called from QgsWFSSourceSelect::on_treeWidget_itemDoubleClicked() to build filters.
 //    a temporary provider object is constructed with a null URI, which bypasses much provider
 //    instantiation logic: refresh(), getFeature(), etc.  therefore, many provider class members
 //    are only default values or uninitialized when running under the source select dialog!
 {
   fields.clear();
-  //Local url or HTTP?  WBC111221 refactored here from getFeature()
+  //Local url or HTTP?
   switch ( mEncoding )
   {
     case QgsWFSProvider::GET:
-    {
       return describeFeatureTypeGET( uri, geometryAttribute, fields, geomType );
-    }
     case QgsWFSProvider::FILE:
-    {
       return describeFeatureTypeFile( uri, geometryAttribute, fields, geomType );
-    }
   }
   QgsDebugMsg( "SHOULD NOT OCCUR: mEncoding undefined" );
   return 1;
@@ -768,7 +753,7 @@ int QgsWFSProvider::getFeatureGET( const QString& uri, const QString& geometryAt
     QObject::connect( this, SIGNAL( dataReadProgressMessage( QString ) ), mainWindow, SLOT( showStatusMessage( QString ) ) );
   }
 
-  if ( dataReader.getWFSData() != 0 )
+  if ( dataReader.getWFSData( mWfsFids ) != 0 )
   {
     QgsDebugMsg( "getWFSData returned with error" );
     return 1;
@@ -777,9 +762,9 @@ int QgsWFSProvider::getFeatureGET( const QString& uri, const QString& geometryAt
   QgsDebugMsg( QString( "feature count after request is: %1" ).arg( mFeatures.size() ) );
   QgsDebugMsg( QString( "mExtent after request is: %1" ).arg( mExtent.toString() ) );
 
-  for ( QMap<QgsFeatureId, QgsFeature*>::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
+  for ( QMap<QgsFeatureId, QgsFeature*>::iterator it = mFeatures.find( mFeatureCount ); it != mFeatures.end(); ++it )
   {
-    QgsDebugMsg( "feature " + FID_TO_STRING(( *it )->id() ) );
+    //QgsDebugMsg( "feature " + FID_TO_STRING(( *it )->id() ) );
     mSpatialIndex->insertFeature( *( it.value() ) );
   }
 
@@ -832,9 +817,7 @@ int QgsWFSProvider::describeFeatureTypeGET( const QString& uri, QString& geometr
 
   mNetworkRequestFinished = false;
 
-  QString describeFeatureUri = uri;
-  describeFeatureUri.replace( QString( "GetFeature" ), QString( "DescribeFeatureType" ) );
-  QNetworkRequest request( describeFeatureUri );
+  QNetworkRequest request( uri );
   QNetworkReply* reply = QgsNetworkAccessManager::instance()->get( request );
   connect( reply, SIGNAL( finished() ), this, SLOT( networkRequestFinished() ) );
   while ( !mNetworkRequestFinished )
@@ -867,7 +850,7 @@ void QgsWFSProvider::networkRequestFinished()
   mNetworkRequestFinished = true;
 }
 
-int QgsWFSProvider::describeFeatureTypeFile( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType )
+int QgsWFSProvider::describeFeatureTypeFile( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType)
 {
   //first look in the schema file
   QString noExtension = uri;
@@ -910,6 +893,7 @@ int QgsWFSProvider::describeFeatureTypeFile( const QString& uri, QString& geomet
 
 int QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc, QString& geometryAttribute, QgsFieldMap& fields, QGis::WkbType& geomType )
 {
+  QgsDebugMsg( schemaDoc.toString() );
   //get the <schema> root element
   QDomNodeList schemaNodeList = schemaDoc.elementsByTagNameNS( "http://www.w3.org/2001/XMLSchema", "schema" );
   if ( schemaNodeList.length() < 1 )
@@ -2323,6 +2307,23 @@ void QgsWFSProvider::getLayerCapabilities()
   }
 
   mCapabilities = capabilities;
+
+  //look for filter capabilities used by incremental get
+  QDomElement e = capabilitiesDocument.elementsByTagNameNS( "http://www.opengis.net/ogc", "Filter_Capabilities" ).item(0).toElement();
+  if ( ! e.tagName().isEmpty() )
+    {
+    mFilterCaps |= Filter;
+    QDomNodeList o = e.elementsByTagNameNS( "http://www.opengis.net/ogc", "Logical_Operators" );
+    if ( o.size() )
+    {
+      mFilterCaps |= LogicOps;
+    }
+    o = e.elementsByTagNameNS( "http://www.opengis.net/ogc", "BBOX" );
+    if ( o.size() )
+    {
+      mFilterCaps |= BBox;
+    }
+  }
 }
 
 void QgsWFSProvider::appendSupportedOperations( const QDomElement& operationsElem, int& capabilities ) const
@@ -2353,14 +2354,16 @@ void QgsWFSProvider::appendSupportedOperations( const QDomElement& operationsEle
 }
 
 //initialization for getRenderedOnly option
-//(formerly "Only request features overlapping the current view extent")
+//[wbc111228 issue 4604: fetch rendered features only]
+//[issue 4280: fetch un-cached features on demand]
 bool QgsWFSProvider::initGetRenderedOnly( const QgsRectangle rect )
 { //find our layer
+  Q_UNUSED( rect );
   QMap<QString, QgsMapLayer*> layers = QgsMapLayerRegistry::instance()->mapLayers();
   QMap<QString, QgsMapLayer*>::const_iterator layersIt = layers.begin();
   for ( ; layersIt != layers.end() ; ++layersIt )
   {
-    if (( mLayer = dynamic_cast<QgsVectorLayer*>( layersIt.value() ) ) )
+    if ( ( mLayer = dynamic_cast<QgsVectorLayer*>( layersIt.value() ) ) )
     {
       if ( mLayer->dataProvider() == this )
       {
@@ -2371,7 +2374,10 @@ bool QgsWFSProvider::initGetRenderedOnly( const QgsRectangle rect )
   }
   if ( layersIt == layers.end() )
   {
-    QgsDebugMsg( "SHOULD NOT OCCUR: initialize() did not find layer." );
+    QgsDebugMsg( QString( "SHOULD NOT OCCUR: initialize() did not find layer for %1." )
+                 .arg( dataSourceUri() ) );
+    QMessageBox::critical ( 0, tr( "Non-Cached layer initialization failed!" ),
+                 tr( "Incorrect operation may occur:\n%1" ).arg( dataSourceUri() ) );
     return false;
   }
   return true;
@@ -2379,27 +2385,239 @@ bool QgsWFSProvider::initGetRenderedOnly( const QgsRectangle rect )
 
 QGis::WkbType QgsWFSProvider::geomTypeFromPropertyType( QString attName, QString propType )
 {
-  const QStringList geomTypes = ( QStringList()
-                                  //all GML v.2.1.3 _geometryProperty group members, except MultiGeometryPropertyType
-                                  //sequence must exactly match enum Qgis::WkbType
-                                  << ""  // unknown geometry, enum 0
-                                  << "Point"
-                                  << "LineString"
-                                  << "Polygon"
-                                  << "MultiPoint"
-                                  << "MultiLineString"
-                                  << "MultiPolygon" );
+  const QStringList geomTypes = ( QStringList ()
+    //all GML v.2.1.3 _geometryProperty group members, except MultiGeometryPropertyType
+    //sequence must exactly match enum Qgis::WkbType
+    << ""  // unknown geometry, enum 0
+    << "Point"
+    << "LineString"
+    << "Polygon"
+    << "MultiPoint"
+    << "MultiLineString"
+    << "MultiPolygon" );
 
   QgsDebugMsg( QString( "DescribeFeatureType geometry attribute \"%1\" type is \"%2\"" )
-               .arg( attName, propType ) );
+                       .arg( attName, propType ) );
   int i = geomTypes.indexOf( propType );
   if ( i <= 0 )
   { // feature type missing or unknown
-    i = ( int ) QGis::WKBUnknown;
+    i = (int) QGis::WKBUnknown;
+  }
+  return (QGis::WkbType) i;
+}
+
+//if not caching whole layer, add features to the cache incrementally
+//as pans and zooms expose new areas on the map canvas
+//[wbc111228 issue 4280: fetch un-cached features on demand]
+void QgsWFSProvider::incrementalGet( QgsRectangle rect )
+{
+ QgsDebugMsg( QString( "\nprevious get extent %1\n      select extent %2" ).arg( mGetExtent.toString(), rect.toString() ) );
+ //has rendered extent expanded beyond last-retrieved WFS extent?
+  //NB: compare overlap area instead of using "contains" function
+  //    avoids double fetch due to rounding error on zoom-in/zoom-out sequences
+  QgsRectangle olap( rect );
+  olap = olap.intersect( &mGetExtent );
+  //is there any overlap between current layer extent and new canvas?
+  //and can WFS provider do ORed BBOX filters?
+  if ( olap.isEmpty() || ( ( mFilterCaps & ( Filter | LogicOps | BBox ) ) !=  ( Filter | LogicOps | BBox ) ) )
+  { //no, discard feature cache and do fresh fetch for new extent
+    QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: fetch replace" ).arg( mLayer->name() ) );
+    //does original URI contain a user-specified filter?
+    if ( mInitUri.contains( "&FILTER=" ) )
+    { //yes, but FILTER & BBOX are mutually exclusive in WSF getFeature URL; merge BBOX into FILTER
+      setDataSourceUri( makeFilteredUri( QList<QgsRectangle>() << rect ) );
+    }
+    else
+    { //URI contains no FILTER; continue with stand-alone BBOX
+      setDataSourceUri( setUriBBox( rect ) );
+    }
+    reloadData();
+    if ( mValid )
+    { //reloadData() cannot set mGetExtent for URI with filter
+      mGetExtent = rect;
+    }
+  }
+  else if ( ( ( rect.width() - olap.width() ) < 1e-6 )
+            && ( ( rect.height() - olap.height() ) < 1e-6 ) )
+  { //difference between canvas and layer extents is less than URL BBOX precision (6 decimal places)
+    QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: no fetch required" ).arg( mLayer->name() ) );
+    return;
   }
-  return ( QGis::WkbType ) i;
+  else
+  { //new canvas extent overlaps old extent: add features in new areas to existing layer
+
+    //compute minimum expansion: at least 1/3 of desired extent in each direction that expands
+    QgsRectangle newGetExt( mGetExtent );
+    newGetExt.combineExtentWith( &rect );
+    double minDeltaX = ( rect.xMaximum() - rect.xMinimum() ) / 3.;
+    double minDeltaY = ( rect.yMaximum() - rect.yMinimum() ) / 3.;
+    if ( rect.xMinimum() < mGetExtent.xMinimum() && rect.xMinimum() > ( mGetExtent.xMinimum() - minDeltaX) )
+    {
+      newGetExt.setXMinimum ( mGetExtent.xMinimum() - minDeltaX );
+    }
+    if ( rect.yMinimum() < mGetExtent.yMinimum() &&  rect.yMinimum() > ( mGetExtent.yMinimum() - minDeltaY) )
+    {
+      newGetExt.setYMinimum ( mGetExtent.yMinimum() - minDeltaY );
+    }
+    if ( rect.xMaximum() > mGetExtent.xMaximum() && rect.xMaximum() < ( mGetExtent.xMaximum() + minDeltaX) )
+    {
+      newGetExt.setXMaximum ( mGetExtent.xMaximum() + minDeltaX );
+    }
+    if ( rect.yMaximum() > mGetExtent.yMaximum() && rect.yMaximum() < ( mGetExtent.yMaximum() + minDeltaY) )
+    {
+      newGetExt.setYMaximum ( mGetExtent.yMaximum() + minDeltaY );
+    }
+
+    //calculate between 1 and 4 rectangles to be fetched around perimeter of existing layer extent
+    QList<QgsRectangle> addArea;
+    if ( newGetExt.xMinimum() < mGetExtent.xMinimum() )
+    { //new area left of current extent
+      addArea.append( QgsRectangle( newGetExt.xMinimum(), mGetExtent.yMinimum(), mGetExtent.xMinimum(), mGetExtent.yMaximum() ) );
+    }
+    if ( newGetExt.yMaximum() > mGetExtent.yMaximum() )
+    { //new area above current extent
+      addArea.append( QgsRectangle( newGetExt.xMinimum(), mGetExtent.yMaximum(), mGetExtent.xMaximum(), newGetExt.yMaximum() ) );
+    }
+    if ( newGetExt.xMaximum() > mGetExtent.xMaximum() )
+    { //new area right of current extent
+      addArea.append( QgsRectangle( mGetExtent.xMaximum(), mGetExtent.yMinimum(), newGetExt.xMaximum(), newGetExt.yMaximum() ) );
+    }
+    if ( newGetExt.yMinimum() < mGetExtent.yMinimum() )
+    { //new area beneath current extent
+      addArea.append( QgsRectangle( newGetExt.xMinimum(), newGetExt.yMinimum(), newGetExt.xMaximum(), mGetExtent.yMinimum() ) );
+    }
+    QgsDebugMsg( QString( "Layer %1 GetRenderedOnly: incremental fetch, %2 areas" ).arg( mLayer->name() ).arg( addArea.size() ) );
+
+    //commented logic below allows duplicate FIDS to pass because some WFS
+    //providers transmit features that do not strictly intersect the BBOX
+    /*get WFS provider IDs of already-fetched features
+    QList<QgsFeatureId> edgeFids;
+    mWfsFids = new QSet<QString>;
+    for ( int i = 0; i < addArea.size() ; ++i )
+    { //identify features extending into each new area
+      edgeFids.append( mSpatialIndex->intersects( addArea[i] ) );
+    }
+    while ( ! edgeFids.isEmpty() )
+    { //collect known WFS provider FIDs of identified
+      mWfsFids->insert( mIdMap.value( edgeFids.takeFirst() ) );
+    }
+    QgsDebugMsg( QString( "WFS FIDs to discard next fetch: %1" ).arg( mWfsFids->size() ) );*/
+    //because of problem above, every known WFS FID is a discard candidate
+    mWfsFids = new QSet<QString>( mIdMap.values().toSet() );
+
+    //save current provider extent (getFeature calls to data reader overwrite mExtent)
+    QgsRectangle saveMExtent( mExtent );
+    //fetch features in new areas, discarding features already fetched
+    setDataSourceUri ( makeFilteredUri( addArea ) );
+    if ( getFeature( dataSourceUri() ) ) //QgsWFSData::endElement discards IDs in mWfsFids
+    { //getFeature failed (timeout, abort); we no longer know the extent actually fetched
+      mValid = false;               //layer is now invalid
+      mGetExtent = QgsRectangle();  //getFeature extent is now unknown
+    }
+    else
+    {
+      mExtent.combineExtentWith ( &saveMExtent ); //sum of extents just received & previously cached
+      mGetExtent = newGetExt;
+    }
+    delete mWfsFids;
+    mWfsFids = 0;
+    //save URI for possible later user refresh()
+    setDataSourceUri ( setUriBBox ( rect ) );
+  }
+  QgsDebugMsg( QString( "features=%1; WSF FIDs=%2; unique WSF FIDs=%3" )
+                        .arg( mFeatures.size() ).arg( mIdMap.size() )
+                        .arg( mIdMap.values().toSet().size() ) );
+}
+
+//transform provider URI to express getFeatures BBOX as FILTER
+QString QgsWFSProvider::makeFilteredUri( QList<QgsRectangle> addArea )
+{
+  //start with initial URI
+  QString uri = mInitUri;
+  //if the user specified a filter, get it
+  QDomElement root;
+  QDomNode n;
+  QDomDocument filter = QDomDocument();
+  QRegExp fre( "&FILTER=(.*)" );  // assumes &FILTER is last argument on URL
+  //does the URI already contain a valid XML filter expression?
+  if ( uri.contains( fre ) && filter.setContent( fre.cap(1) ) )
+  { //yes, create insertion point to AND a BBOX filter
+    root = filter.firstChild().toElement(); // <Filter> element
+    QDomNode userFilter = root.removeChild( root.firstChild() );
+    n = root.appendChild( filter.createElement( "And" ) );
+    n.appendChild( userFilter );
+    QgsDebugMsg( QString( "filter=%1" ).arg( filter.toString() ) );
+  }
+  else
+  { //no, create new OGC XML Filter
+    QDomElement root =  filter.createElement( "Filter" );
+    n = filter.appendChild( root );
+  }
+  //define namespace for "Box" and "coordinates"
+  root.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
+  //OR a new BBOX clause (ver. 1.0.0) for each new area
+  if ( addArea.size() > 1 )
+  {
+    n = n.appendChild( filter.createElement( "Or" ) );
+  }
+  while ( ! addArea.isEmpty() )
+  {
+    QDomNode b = n.appendChild( filter.createElement( "BBOX" ) );
+    QDomElement p = filter.createElement("PropertyName" );
+    p.appendChild( filter.createTextNode( mGeometryAttribute ) );
+    b.appendChild( p );
+    //filter XML v. 1.0.0 -- accepted but ignored on some arcgis systems [wbc121130]
+    QDomElement v = filter.createElement( "gml:Box" );
+    v.setAttribute( "srsName", mSourceCRS.authid() );
+    QDomNode e = b.appendChild( v );
+    QDomNode c = e.appendChild( filter.createElement( "gml:coordinates" ) );
+    QgsRectangle delta = addArea.takeFirst();
+    c.appendChild( filter.createTextNode( QString( "%1,%2 %3,%4" )
+                  .arg( delta.xMinimum(), 0, 'f').arg(delta.yMinimum(), 0, 'f')
+                  .arg( delta.xMaximum(), 0, 'f').arg(delta.yMaximum(), 0, 'f') ) );
+  }
+  QgsDebugMsg( QString( "filter=%1" ).arg( filter.toString() ) );
+
+  //get features contained in each new area
+  uri.replace( QRegExp( "BBOX=.*" ), QString( "FILTER=%1" ).arg( filter.toString( -1 ) ) );
+  return uri;
 }
 
+QString QgsWFSProvider::setUriBBox( QgsRectangle rect )
+{
+  QgsDebugMsg( QString( "layer %1 GetRenderedOnly: fetching extent %2" )
+              .arg( mLayer->name(), rect.asWktCoordinates() ) );
+  QString dsURI = mInitUri;
+  dsURI = dsURI.replace( QRegExp( "BBOX=[^&]*" ),
+                          QString( "BBOX=%1,%2,%3,%4" )
+                          .arg( rect.xMinimum(), 0, 'f' )
+                          .arg( rect.yMinimum(), 0, 'f' )
+                          .arg( rect.xMaximum(), 0, 'f' )
+                          .arg( rect.yMaximum(), 0, 'f' ) );
+  return dsURI;
+}
+
+QgsRectangle QgsWFSProvider::getUriBBox()
+{
+  bool ok = true;
+  QRegExp uriBBox( "&BBOX=(([-+.0-9]+,?){4})" );
+  if ( dataSourceUri().contains( uriBBox ) )
+  {
+    QList<QString> coords = uriBBox.cap(1).split( "," );
+    QList<double> coordd;
+    while ( ok && ! coords.isEmpty() )
+    {
+      coordd.append( coords.takeFirst().toDouble( &ok ) );
+    }
+    if ( ok )
+    {
+      return QgsRectangle( coordd[0], coordd[1], coordd[2], coordd[3] );
+    }
+  }
+  return QgsRectangle();
+}
+//[end issue 4280]
+
 void QgsWFSProvider::handleException( const QDomDocument& serverResponse ) const
 {
   QDomElement exceptionElem = serverResponse.documentElement();
@@ -2435,4 +2653,4 @@ QGISEXTERN QString description()
 QGISEXTERN bool isProvider()
 {
   return true;
-}
+}
\ No newline at end of file
diff --git a/src/providers/wfs/qgswfsprovider.h b/src/providers/wfs/qgswfsprovider.h
index ac2d9e7..2eb941d 100644
--- a/src/providers/wfs/qgswfsprovider.h
+++ b/src/providers/wfs/qgswfsprovider.h
@@ -160,6 +160,19 @@ class QgsWFSProvider: public QgsVectorDataProvider
   private:
     bool mNetworkRequestFinished;
 
+    /**WFS Filter capabilities of interest to data provider*/
+    enum FilterCap
+    {
+      /** no filter capabilities advertised */
+      NoFilter =          0,
+      /** ogc:Filter_Capabilities advertised */
+      Filter =            1,
+      /** ogc:Logical_Operators advertised */
+      LogicOps =     1 << 1,
+      /** ogc:BBOX advertised */
+      BBox =         1 << 2,
+    };
+
   protected:
     /**Thematic attributes*/
     QgsFieldMap mFields;
@@ -196,12 +209,16 @@ class QgsWFSProvider: public QgsVectorDataProvider
     int mCapabilities;
     /**GetRenderedOnly: layer asociated with this provider*/
     QgsVectorLayer *mLayer;
-    /**GetRenderedOnly: fetch only features within canvas extent to be rendered*/
+    /**GetRenderedOnly option flag [wbc111228 issue 4604: fetch rendered features only]*/
     bool mGetRenderedOnly;
-    /**GetRenderedOnly initializaiton flat*/
-    bool mInitGro;
+    /**GetRenderedOnly initial URI*/
+    QString mInitUri;
     /**if GetRenderedOnly, extent specified in WFS getFeatures; else empty (no constraint)*/
     QgsRectangle mGetExtent;
+    /**incremental get: known FIDs [wbc111228 issue 4280: fetch un-cached features on demand]*/
+    QSet<QString> *mWfsFids;
+    /**WFS filter capabilities of interest to data provider*/
+    int mFilterCaps;
 
     //encoding specific methods of getFeature
     int getFeatureGET( const QString& uri, const QString& geometryAttribute );
@@ -295,10 +312,18 @@ class QgsWFSProvider: public QgsVectorDataProvider
     void appendSupportedOperations( const QDomElement& operationsElem, int& capabilities ) const;
     /**Shows a message box with the exception string (or does nothing if the xml document is not an exception)*/
     void handleException( const QDomDocument& serverResponse ) const;
-    /**Initializes "Cache Features" inactive processing*/
+    /**Initialize getRenderedOnly option*/
     bool initGetRenderedOnly( QgsRectangle );
-    /**Converts DescribeFeatureType schema geometry property type to WKBType*/
+    /**Convert DescribeFeatureType schema geometry property type to WKBType*/
     QGis::WkbType geomTypeFromPropertyType( QString attName, QString propType );
+    /**Fetch features from WSF provider for canvas areas to be rendered*/
+    void incrementalGet( QgsRectangle rect );
+    /**convert URI BBOX into filter expression*/
+    QString makeFilteredUri( QList<QgsRectangle> addArea );
+    /**Update BBOX parameter in GetFeature URI*/
+    QString setUriBBox ( QgsRectangle rect );
+    /**Extract BBOX from dataSourceUri()*/
+    QgsRectangle getUriBBox ();
 
     void deleteData();
 };
diff --git a/src/providers/wfs/qgswfssourceselect.cpp b/src/providers/wfs/qgswfssourceselect.cpp
index dcf6c58..f10d48b 100644
--- a/src/providers/wfs/qgswfssourceselect.cpp
+++ b/src/providers/wfs/qgswfssourceselect.cpp
@@ -59,6 +59,7 @@ QgsWFSSourceSelect::QgsWFSSourceSelect( QWidget* parent, Qt::WFlags fl, bool emb
   connect( btnConnect, SIGNAL( clicked() ), this, SLOT( connectToServer() ) );
   connect( btnChangeSpatialRefSys, SIGNAL( clicked() ), this, SLOT( changeCRS() ) );
   connect( treeWidget, SIGNAL( currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* ) ), this, SLOT( changeCRSFilter() ) );
+  connect( treeWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( setApplyButton() ) );
   populateConnectionList();
   mProjectionSelector = new QgsGenericProjectionSelector( this );
   mProjectionSelector->setMessage();
@@ -189,16 +190,36 @@ void QgsWFSSourceSelect::capabilitiesReplyFinished()
     }
     mAvailableCRS.insert( std::make_pair( featureType.name, currentCRSList ) );
   }
+  treeWidget->resizeColumnToContents( 0 );
+  treeWidget->sortItems( 0, Qt::AscendingOrder );
 
   if ( caps.featureTypes.count() > 0 )
   {
-    btnAdd->setEnabled( true );
-    treeWidget->setCurrentItem( treeWidget->topLevelItem( 0 ) );
     btnChangeSpatialRefSys->setEnabled( true );
+    if ( caps.featureTypes.count() == 1 )
+    { //if only one item, select it; otherwise, user must select all desired items
+      treeWidget->setCurrentItem( treeWidget->topLevelItem( 0 ) );
+    }
+    if ( ! caps.canFilter )
+    { //if WFS provider does not advertise filter capability, delete "Filter" column
+      treeWidget->setColumnCount(4);
+    }
   }
   else
   {
     QMessageBox::information( 0, tr( "No Layers" ), tr( "capabilities document contained no layers." ) );
+  }
+}
+
+//enable Apply button when one or more layers are selected
+void QgsWFSSourceSelect::setApplyButton()
+{
+  if ( treeWidget->selectedItems().size() )
+  {
+    btnAdd->setEnabled( true );
+  }
+  else
+  {
     btnAdd->setEnabled( false );
   }
 }
@@ -266,7 +287,8 @@ void QgsWFSSourceSelect::addLayer()
   QgsWFSConnection conn( cmbConnections->currentText() );
   QString pCrsString( labelCoordRefSys->text() );
   QgsCoordinateReferenceSystem pCrs( pCrsString );
-  //prepare canvas extent info for layers with "cache features" option not set
+
+  //prepare canvas extent info [wbc111228 issue 4604: fetch rendered features only]
   QgsRectangle extent;
   QVariant extentVariant = property( "MapExtent" );
   if ( extentVariant.isValid() )
@@ -294,18 +316,19 @@ void QgsWFSSourceSelect::addLayer()
       {
         QgsCoordinateTransform xform( pCrs, cCrs );
         extent = xform.transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
-        QgsDebugMsg( QString( "canvas transform: Canvas CRS=%1, Provider CRS=%2, BBOX=%3" )
-                     .arg( cCrs.authid(), pCrs.authid(), extent.asWktCoordinates() ) );
+        QgsDebugMsg( QString("canvas transform: Canvas CRS=%1, Provider CRS=%2, BBOX=%3")
+                             .arg(cCrs.authid(), pCrs.authid(), extent.asWktCoordinates() ) );
       }
     }
   }
+
   //create layers that user selected from this WFS source
   for ( ; sIt != selectedItems.constEnd(); ++sIt )
   { //add a wfs layer to the map
     QString typeName = ( *sIt )->text( 1 );  //WFS repository's name for layer
     QString filter = ( *sIt )->text( 4 );    //optional filter specified by user
-    //is "cache features" checked?
-    if (( *sIt )->checkState( 3 ) == Qt::Checked )
+    //is "cache all features" checked?
+    if ( ( *sIt )->checkState( 3 ) == Qt::Checked )
     { //yes: entire WFS layer will be retrieved and cached
       mUri = conn.uriGetFeature( typeName, pCrsString, filter );
     }
diff --git a/src/providers/wfs/qgswfssourceselect.h b/src/providers/wfs/qgswfssourceselect.h
index 8342f3d..d928e7a 100644
--- a/src/providers/wfs/qgswfssourceselect.h
+++ b/src/providers/wfs/qgswfssourceselect.h
@@ -70,6 +70,7 @@ class QgsWFSSourceSelect: public QDialog, private Ui::QgsWFSSourceSelectBase
     void on_btnSave_clicked();
     void on_btnLoad_clicked();
     void on_treeWidget_itemDoubleClicked( QTreeWidgetItem* item, int column );
+    void setApplyButton();
 
     void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }
 
diff --git a/src/ui/qgswfssourceselectbase.ui b/src/ui/qgswfssourceselectbase.ui
index e23dd64..859f296 100644
--- a/src/ui/qgswfssourceselectbase.ui
+++ b/src/ui/qgswfssourceselectbase.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>592</width>
-    <height>439</height>
+    <width>600</width>
+    <height>450</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -105,20 +105,53 @@
    </item>
    <item row="1" column="0">
     <widget class="QTreeWidget" name="treeWidget">
+     <property name="baseSize">
+      <size>
+       <width>0</width>
+       <height>0</height>
+      </size>
+     </property>
      <property name="selectionMode">
       <enum>QAbstractItemView::ExtendedSelection</enum>
      </property>
+     <property name="textElideMode">
+      <enum>Qt::ElideRight</enum>
+     </property>
      <property name="sortingEnabled">
       <bool>true</bool>
      </property>
      <property name="columnCount">
       <number>5</number>
      </property>
+     <attribute name="headerCascadingSectionResizes">
+      <bool>true</bool>
+     </attribute>
+     <attribute name="headerDefaultSectionSize">
+      <number>80</number>
+     </attribute>
+     <attribute name="headerHighlightSections">
+      <bool>true</bool>
+     </attribute>
      <attribute name="headerMinimumSectionSize">
-      <number>27</number>
+      <number>60</number>
+     </attribute>
+     <attribute name="headerStretchLastSection">
+      <bool>true</bool>
+     </attribute>
+     <attribute name="headerCascadingSectionResizes">
+      <bool>true</bool>
+     </attribute>
+     <attribute name="headerDefaultSectionSize">
+      <number>80</number>
      </attribute>
      <attribute name="headerMinimumSectionSize">
-      <number>27</number>
+      <number>60</number>
+     </attribute>
+     <attribute name="headerHighlightSections">
+      <bool>true</bool>
+     </attribute>
+     <attribute name="headerStretchLastSection">
+      <bool>true</bool>
      </attribute>
      <column>
       <property name="text">
@@ -137,16 +170,22 @@
      </column>
      <column>
       <property name="text">
-       <string>Cache
+       <string>Cache All
 Features</string>
       </property>
+      <property name="toolTip">
+       <string extracomment="Retrieve all features from WFS repository when layer is created."/>
+      </property>
+      <property name="statusTip">
+       <string extracomment="Caution: &lt;b&gt;slow&lt;/b&gt; layer creation from large remote WFS providers!"/>
+      </property>
       <property name="textAlignment">
-       <set>AlignHCenter|AlignVCenter|AlignCenter</set>
+       <set>AlignLeft|AlignVCenter</set>
       </property>
      </column>
      <column>
       <property name="text">
-       <string>Filter</string>
+       <string>Filter (double click to enter)</string>
       </property>
      </column>
     </widget>
