Skip to content

Commit a941f4a

Browse files
committedDec 13, 2011
Merge branch 'wfs_filter'
2 parents 700e6b4 + 05fd598 commit a941f4a

10 files changed

+243
-46
lines changed
 

‎src/app/qgisapp.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,6 +2444,11 @@ void QgisApp::addWfsLayer()
24442444
connect( wfss , SIGNAL( addWfsLayer( QString, QString ) ),
24452445
this , SLOT( addWfsLayer( QString, QString ) ) );
24462446

2447+
if ( mapCanvas() )
2448+
{
2449+
wfss->setProperty( "MapExtent", mapCanvas()->extent().toString() ); //hack to reenable wfs with extent setting
2450+
}
2451+
24472452
wfss->exec();
24482453
delete wfss;
24492454
}

‎src/core/qgsexpression.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "qgsexpression.h"
1717

1818
#include <QtDebug>
19+
#include <QDomDocument>
1920
#include <QSettings>
2021
#include <math.h>
2122

@@ -968,3 +969,97 @@ QString QgsExpression::NodeColumnRef::dump() const
968969
{
969970
return mName;
970971
}
972+
973+
bool QgsExpression::toOGCFilter( QDomDocument& doc ) const
974+
{
975+
if ( !mRootNode )
976+
{
977+
return false;
978+
}
979+
980+
doc.clear();
981+
QDomElement filterElem = doc.createElement( "Filter" );
982+
doc.appendChild( filterElem );
983+
return mRootNode->toOGCFilter( doc, filterElem );
984+
}
985+
986+
bool QgsExpression::NodeBinaryOperator::toOGCFilter( QDomDocument& doc, QDomElement& parent ) const
987+
{
988+
QDomElement opElem;
989+
switch ( mOp )
990+
{
991+
case boEQ:
992+
opElem = doc.createElement( "PropertyIsEqualTo" );
993+
break;
994+
case boNE:
995+
opElem = doc.createElement( "PropertyIsNotEqualTo" );
996+
break;
997+
case boLE:
998+
opElem = doc.createElement( "PropertyIsLessThanOrEqualTo" );
999+
break;
1000+
case boGE:
1001+
opElem = doc.createElement( "PropertyIsLessThanOrEqualTo" );
1002+
break;
1003+
case boLT:
1004+
opElem = doc.createElement( "PropertyIsLessThan" );
1005+
break;
1006+
case boGT:
1007+
opElem = doc.createElement( "PropertyIsGreaterThan" );
1008+
break;
1009+
case boOr:
1010+
opElem = doc.createElement( "Or" );
1011+
break;
1012+
case boAnd:
1013+
opElem = doc.createElement( "And" );
1014+
break;
1015+
default:
1016+
return false;
1017+
}
1018+
1019+
if ( mOpLeft )
1020+
{
1021+
mOpLeft->toOGCFilter( doc, opElem );
1022+
}
1023+
if ( mOpRight )
1024+
{
1025+
mOpRight->toOGCFilter( doc, opElem );
1026+
}
1027+
1028+
parent.appendChild( opElem );
1029+
return true;
1030+
}
1031+
1032+
bool QgsExpression::NodeLiteral::toOGCFilter( QDomDocument& doc, QDomElement& parent ) const
1033+
{
1034+
QDomElement literalElem = doc.createElement( "Literal" );
1035+
QDomText literalText = doc.createTextNode( mValue.toString() );
1036+
literalElem.appendChild( literalText );
1037+
parent.appendChild( literalElem );
1038+
return true;
1039+
}
1040+
1041+
bool QgsExpression::NodeColumnRef::toOGCFilter( QDomDocument& doc, QDomElement& parent ) const
1042+
{
1043+
QDomElement propertyElem = doc.createElement( "PropertyName" );
1044+
QDomText propertyText = doc.createTextNode( mName );
1045+
propertyElem.appendChild( propertyText );
1046+
parent.appendChild( propertyElem );
1047+
return true;
1048+
}
1049+
1050+
bool QgsExpression::NodeUnaryOperator::toOGCFilter( QDomDocument& doc, QDomElement& parent ) const
1051+
{
1052+
if ( mOp == uoNot )
1053+
{
1054+
QDomElement notElem = doc.createElement( "Not" );
1055+
if ( mOperand )
1056+
{
1057+
if ( mOperand->toOGCFilter( doc, notElem ) )
1058+
{
1059+
parent.appendChild( notElem );
1060+
return true;
1061+
}
1062+
}
1063+
}
1064+
return false;
1065+
}

‎src/core/qgsexpression.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
class QgsDistanceArea;
2626
class QgsFeature;
27+
class QDomDocument;
28+
class QDomElement;
2729

2830
/**
2931
Class for parsing and evaluation of expressions (formerly called "search strings").
@@ -120,6 +122,9 @@ class CORE_EXPORT QgsExpression
120122

121123
//! Return the parsed expression as a string - useful for debugging
122124
QString dump() const;
125+
//! Creates ogc filter xml document. Supports minimum standard filter according to the OGC filter specs (=,!=,<,>,<=,>=,AND,OR,NOT)
126+
//! @return true in case of success. False if string contains something that goes beyond the minimum standard filter
127+
bool toOGCFilter( QDomDocument& doc ) const;
123128

124129
//! Return calculator used for distance and area calculations
125130
//! (used by internal functions)
@@ -222,6 +227,7 @@ class CORE_EXPORT QgsExpression
222227

223228
virtual QStringList referencedColumns() const = 0;
224229
virtual bool needsGeometry() const = 0;
230+
virtual bool toOGCFilter( QDomDocument& doc, QDomElement& parent ) const { return false; }
225231
};
226232

227233
class NodeList
@@ -249,6 +255,7 @@ class CORE_EXPORT QgsExpression
249255
virtual QString dump() const;
250256
virtual QStringList referencedColumns() const { return mOperand->referencedColumns(); }
251257
virtual bool needsGeometry() const { return mOperand->needsGeometry(); }
258+
virtual bool toOGCFilter( QDomDocument& doc, QDomElement& parent ) const;
252259
protected:
253260
UnaryOperator mOp;
254261
Node* mOperand;
@@ -265,6 +272,8 @@ class CORE_EXPORT QgsExpression
265272
virtual QString dump() const;
266273
virtual QStringList referencedColumns() const { return mOpLeft->referencedColumns() + mOpRight->referencedColumns(); }
267274
virtual bool needsGeometry() const { return mOpLeft->needsGeometry() || mOpRight->needsGeometry(); }
275+
virtual bool toOGCFilter( QDomDocument& doc, QDomElement& parent ) const;
276+
268277
protected:
269278
bool compare( double diff );
270279
int computeInt( int x, int y );
@@ -320,6 +329,7 @@ class CORE_EXPORT QgsExpression
320329
virtual QString dump() const;
321330
virtual QStringList referencedColumns() const { return QStringList(); }
322331
virtual bool needsGeometry() const { return false; }
332+
virtual bool toOGCFilter( QDomDocument& doc, QDomElement& parent ) const;
323333
protected:
324334
QVariant mValue;
325335
};
@@ -334,6 +344,7 @@ class CORE_EXPORT QgsExpression
334344
virtual QString dump() const;
335345
virtual QStringList referencedColumns() const { return QStringList( mName ); }
336346
virtual bool needsGeometry() const { return false; }
347+
virtual bool toOGCFilter( QDomDocument& doc, QDomElement& parent ) const;
337348
protected:
338349
QString mName;
339350
int mIndex;

‎src/providers/wfs/qgswfsconnection.cpp

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
#include "qgswfsconnection.h"
2-
2+
#include "qgsexpression.h"
33
#include "qgslogger.h"
4-
5-
#include <QDomDocument>
6-
#include <QSettings>
7-
#include <QStringList>
8-
94
#include "qgsnetworkaccessmanager.h"
5+
#include <QDomDocument>
106
#include <QNetworkRequest>
117
#include <QNetworkReply>
8+
#include <QSettings>
9+
#include <QStringList>
1210

1311
static const QString WFS_NAMESPACE = "http://www.opengis.net/wfs";
1412

@@ -36,12 +34,17 @@ QgsWFSConnection::QgsWFSConnection( QString connName, QObject *parent ) :
3634
}
3735
}
3836

39-
QString QgsWFSConnection::uriGetCapabilities()
37+
QString QgsWFSConnection::uriGetCapabilities() const
4038
{
4139
return mUri + "SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0";
4240
}
4341

44-
QString QgsWFSConnection::uriGetFeature( QString typeName, QString crsString, QString filter, QgsRectangle bBox )
42+
QString QgsWFSConnection::uriDescribeFeatureType( const QString& typeName ) const
43+
{
44+
return mUri + "SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=" + typeName;
45+
}
46+
47+
QString QgsWFSConnection::uriGetFeature( QString typeName, QString crsString, QString filter, QgsRectangle bBox ) const
4548
{
4649
//get CRS
4750
if ( !crsString.isEmpty() )
@@ -50,9 +53,29 @@ QString QgsWFSConnection::uriGetFeature( QString typeName, QString crsString, QS
5053
}
5154

5255
QString filterString;
56+
57+
//if the xml comes from the dialog, it needs to be a string to pass the validity test
58+
if ( filter.startsWith( "'" ) && filter.endsWith( "'" ) && filter.size() > 1 )
59+
{
60+
filter.chop( 1 );
61+
filter.remove( 0, 1 );
62+
}
63+
5364
if ( !filter.isEmpty() )
5465
{
55-
filterString = "&FILTER=" + filter;
66+
//test if filterString is already an OGC filter xml
67+
QDomDocument filterDoc;
68+
if ( !filterDoc.setContent( filter ) )
69+
{
70+
//if not, if must be a QGIS expression
71+
QgsExpression filterExpression( filter );
72+
if ( !filterExpression.toOGCFilter( filterDoc ) )
73+
{
74+
//error
75+
}
76+
77+
}
78+
filterString = "&FILTER=" + filterDoc.toString();
5679
}
5780

5881
QString bBoxString;

‎src/providers/wfs/qgswfsconnection.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ class QgsWFSConnection : public QObject
2121
static void setSelectedConnection( QString name );
2222

2323
//! base service URI
24-
QString uri() { return mUri; }
24+
QString uri() const { return mUri; }
2525
//! URI to get capabilities
26-
QString uriGetCapabilities();
26+
QString uriGetCapabilities() const;
27+
//! URI to get schema of wfs layer
28+
QString uriDescribeFeatureType( const QString& typeName ) const;
2729
//! URI to get features
30+
//! @param filter can be an OGC filter xml or a QGIS expression (containing =,!=, <,>,<=, >=, AND, OR, NOT )
2831
QString uriGetFeature( QString typeName,
2932
QString crs = QString(),
3033
QString filter = QString(),
31-
QgsRectangle bBox = QgsRectangle() );
34+
QgsRectangle bBox = QgsRectangle() ) const;
3235

3336
//! start network connection to get capabilities
3437
void requestCapabilities();

‎src/providers/wfs/qgswfsprovider.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,19 @@ static const QString GML_NAMESPACE = "http://www.opengis.net/gml";
4747
QgsWFSProvider::QgsWFSProvider( const QString& uri )
4848
: QgsVectorDataProvider( uri ),
4949
mNetworkRequestFinished( true ),
50+
mEncoding( QgsWFSProvider::GET ),
5051
mUseIntersect( false ),
5152
mSourceCRS( 0 ),
5253
mFeatureCount( 0 ),
5354
mValid( true )
5455
{
5556
mSpatialIndex = 0;
57+
if ( uri.isEmpty() )
58+
{
59+
mValid = false;
60+
return;
61+
}
62+
5663
reloadData();
5764
if ( mValid )
5865
{

‎src/providers/wfs/qgswfsprovider.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ class QgsWFSProvider: public QgsVectorDataProvider
140140
synchronize with changes in the data source*/
141141
virtual void reloadData();
142142

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+
143146
signals:
144147
void dataReadProgressMessage( QString message );
145148

@@ -189,10 +192,6 @@ class QgsWFSProvider: public QgsVectorDataProvider
189192
/**Server capabilities for this layer (generated from capabilities document)*/
190193
int mCapabilities;
191194

192-
193-
/**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*/
194-
int describeFeatureType( const QString& uri, QString& geometryAttribute, QgsFieldMap& fields );
195-
196195
//encoding specific methods of getFeature
197196
int getFeatureGET( const QString& uri, const QString& geometryAttribute );
198197
int getFeaturePOST( const QString& uri, const QString& geometryAttribute );

‎src/providers/wfs/qgswfssourceselect.cpp

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
#include "qgisinterface.h"
1919
#include "qgswfssourceselect.h"
2020
#include "qgswfsconnection.h"
21+
#include "qgswfsprovider.h"
2122
#include "qgsnewhttpconnection.h"
2223
#include "qgsgenericprojectionselector.h"
24+
#include "qgsexpressionbuilderdialog.h"
2325
#include "qgscontexthelp.h"
2426
#include "qgsproject.h"
2527
#include "qgscoordinatereferencesystem.h"
@@ -49,10 +51,6 @@ QgsWFSSourceSelect::QgsWFSSourceSelect( QWidget* parent, Qt::WFlags fl, bool emb
4951
buttonBox->button( QDialogButtonBox::Cancel )->hide();
5052
}
5153

52-
// keep the "use current view extent" checkbox hidden until
53-
// the functionality is reintroduced [MD]
54-
mBboxCheckBox->hide();
55-
5654
connect( buttonBox, SIGNAL( accepted() ), this, SLOT( addLayer() ) );
5755
connect( buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
5856
connect( btnNew, SIGNAL( clicked() ), this, SLOT( addEntryToServerList() ) );
@@ -263,27 +261,24 @@ void QgsWFSSourceSelect::addLayer()
263261
}
264262

265263
QgsRectangle bBox;
266-
#if 0
267-
// TODO: resolve [MD]
268-
//get current extent
269-
QgsMapCanvas* canvas = mIface->mapCanvas();
270-
if ( canvas && mBboxCheckBox->isChecked() )
264+
QgsRectangle currentRectangle;
265+
if ( mBboxCheckBox->isChecked() )
271266
{
272-
QgsRectangle currentExtent = canvas->extent();
267+
currentRectangle = mExtent;
273268
}
274-
#endif
269+
275270

276271
QList<QTreeWidgetItem*> selectedItems = treeWidget->selectedItems();
277272
QList<QTreeWidgetItem*>::const_iterator sIt = selectedItems.constBegin();
278273
for ( ; sIt != selectedItems.constEnd(); ++sIt )
279274
{
280275
QString typeName = ( *sIt )->text( 1 );
281276
QString crs = labelCoordRefSys->text();
282-
QString filter = mFilterLineEdit->text();
277+
QString filter = ( *sIt )->text( 3 );
283278

284279
//add a wfs layer to the map
285280
QgsWFSConnection conn( cmbConnections->currentText() );
286-
QString uri = conn.uriGetFeature( typeName, crs, filter, bBox );
281+
QString uri = conn.uriGetFeature( typeName, crs, filter, currentRectangle );
287282
emit addWfsLayer( uri, typeName );
288283
}
289284
}
@@ -364,3 +359,65 @@ void QgsWFSSourceSelect::on_btnLoad_clicked()
364359
populateConnectionList();
365360
emit connectionsChanged();
366361
}
362+
363+
void QgsWFSSourceSelect::on_treeWidget_itemDoubleClicked( QTreeWidgetItem* item, int column )
364+
{
365+
if ( item && column == 3 )
366+
{
367+
//get available fields for wfs layer
368+
QgsWFSProvider p( "" );
369+
QgsWFSConnection conn( cmbConnections->currentText() );
370+
QString uri = conn.uriDescribeFeatureType( item->text( 1 ) );
371+
372+
QgsFieldMap fields;
373+
QString geometryAttribute;
374+
if ( p.describeFeatureType( uri, geometryAttribute, fields ) != 0 )
375+
{
376+
return;
377+
}
378+
379+
380+
//show expression builder
381+
QgsExpressionBuilderDialog d( 0, item->text( 3 ) );
382+
383+
//add available attributes to expression builder
384+
QgsExpressionBuilderWidget* w = d.expressionBuilder();
385+
if ( !w )
386+
{
387+
return;
388+
}
389+
390+
QgsFieldMap::const_iterator fieldIt = fields.constBegin();
391+
for ( ; fieldIt != fields.constEnd(); ++fieldIt )
392+
{
393+
w->registerItem( tr( "Fields" ), fieldIt->name(), " " + fieldIt->name() + " ", "", QgsExpressionItem::Field );
394+
}
395+
396+
if ( d.exec() == QDialog::Accepted )
397+
{
398+
item->setText( 3, w->getExpressionString() );
399+
}
400+
}
401+
}
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+
mBboxCheckBox->hide();
423+
}

‎src/providers/wfs/qgswfssourceselect.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "ui_qgswfssourceselectbase.h"
2222
#include "qgscontexthelp.h"
23+
#include "qgsrectangle.h"
2324

2425
class QgsGenericProjectionSelector;
2526
class QgsWFSConnection;
@@ -46,6 +47,7 @@ class QgsWFSSourceSelect: public QDialog, private Ui::QgsWFSSourceSelectBase
4647
std::map<QString, std::list<QString> > mAvailableCRS;
4748
QAbstractButton* btnAdd;
4849
QgsWFSConnection* mConn;
50+
QgsRectangle mExtent;
4951

5052
void populateConnectionList();
5153

@@ -68,8 +70,12 @@ class QgsWFSSourceSelect: public QDialog, private Ui::QgsWFSSourceSelectBase
6870
void capabilitiesReplyFinished();
6971
void on_btnSave_clicked();
7072
void on_btnLoad_clicked();
73+
void on_treeWidget_itemDoubleClicked( QTreeWidgetItem* item, int column );
7174

7275
void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }
76+
77+
protected:
78+
void showEvent( QShowEvent* event );
7379
};
7480

7581
#endif

‎src/ui/qgswfssourceselectbase.ui

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,13 @@
106106
<item row="1" column="0">
107107
<widget class="QTreeWidget" name="treeWidget">
108108
<property name="selectionMode">
109-
<enum>QAbstractItemView::MultiSelection</enum>
109+
<enum>QAbstractItemView::ExtendedSelection</enum>
110110
</property>
111111
<property name="sortingEnabled">
112112
<bool>true</bool>
113113
</property>
114114
<property name="columnCount">
115-
<number>3</number>
115+
<number>4</number>
116116
</property>
117117
<column>
118118
<property name="text">
@@ -129,6 +129,11 @@
129129
<string>Abstract</string>
130130
</property>
131131
</column>
132+
<column>
133+
<property name="text">
134+
<string>Filter</string>
135+
</property>
136+
</column>
132137
</widget>
133138
</item>
134139
<item row="2" column="0">
@@ -180,27 +185,13 @@
180185
</widget>
181186
</item>
182187
<item row="3" column="0">
183-
<layout class="QHBoxLayout" name="horizontalLayout_2">
184-
<item>
185-
<widget class="QLabel" name="mFilterStringLabel">
186-
<property name="text">
187-
<string>Filter</string>
188-
</property>
189-
</widget>
190-
</item>
191-
<item>
192-
<widget class="QLineEdit" name="mFilterLineEdit"/>
193-
</item>
194-
</layout>
195-
</item>
196-
<item row="4" column="0">
197188
<widget class="QCheckBox" name="mBboxCheckBox">
198189
<property name="text">
199190
<string>Only request features overlapping the current view extent</string>
200191
</property>
201192
</widget>
202193
</item>
203-
<item row="5" column="0">
194+
<item row="4" column="0">
204195
<widget class="QDialogButtonBox" name="buttonBox">
205196
<property name="orientation">
206197
<enum>Qt::Horizontal</enum>

0 commit comments

Comments
 (0)
Please sign in to comment.