Skip to content

Commit

Permalink
Enable Search combo to work with WSGI scripts (as with original QWC)
Browse files Browse the repository at this point in the history
WSGI configuration read from json file
Update WSGI scripts (transform geometry on server side to match Map CRS)
Match Geocode search combo with QGIS Search combo (WSGI)
  • Loading branch information
uprel committed Dec 17, 2017
1 parent 774ad62 commit 4d4ddc1
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 78 deletions.
66 changes: 44 additions & 22 deletions client/README
Original file line number Diff line number Diff line change
Expand Up @@ -726,62 +726,73 @@ GlobalOptions.js see the example below:
Permalinks: the permalinks script is not yet implemented in PHP.


6.2. WSGI Search
6.2. WSGI Search
================


6.2.1. Configuration of mod_wsgi
6.2.1. Configuration of mod_wsgi
================================

You need to enable mod_wsgi as root. (Ubuntu: a2enmod mod_wsgi).
You need to enable mod_wsgi as root. (Ubuntu: a2enmod wsgi).
If you get error module not exist, installation is missing (Ubuntu: apt-get install libapache2-mod-wsgi)

Install also this:
(Ubuntu: apt-get install python-webob)

You need to configure apache with the following lines (e.g. in file
/etc/apache2/sites-available/default):
``/etc/apache2/sites-available/default``):

::

#mod_wsgi
WSGIDaemonProcess gis processes=5 threads=15 display-name=%{GROUP}
WSGIScriptAlias /wsgi/ /home/www/wsgi/
WSGIScriptAliasMatch ^/wsgi/([^/]+) /home/www/wsgi/$1.wsgi
#Have to comment this
#WSGIDaemonProcess gis processes=5 threads=15 display-name=%{GROUP}
WSGIScriptAlias /wsgi/ /var/www/html/gisapp/client/wsgi/
WSGIScriptAliasMatch ^/wsgi/([^/]+) /var/www/html/gisapp/client/wsgi/$1.wsgi


6.2.2. Adaption of the wsgi scripts to your settings and needs
6.2.2. Adaption of the wsgi scripts to your settings and needs
==============================================================


6.2.2.1. DB connection
6.2.2.1. DB connection
======================

In the file qwc_connect.py please edit the first line containing the db connection string.
In the file ``qwc_connect.py`` please edit the first line containing the db connection string.

DB_CONN_STRING="host='myhost' dbname='mydb' port='5432' user='myuser' password='secret'"
``DB_CONN_STRING="host='myhost' dbname='mydb' port='5432' user='myuser' password='secret'"``

This connection will be used in all wsgi scripts.

Adapt the parameters according to your server/db. It is highly recommended to
connect with a database user having limited rights only (e.g. select rights on relevant tables only).


6.2.2.2. Search type to be used
6.2.2.2. Search type to be used
===============================

The search can use PostgreSQL's tsvector data type.
"A tsvector value is a sorted list of distinct lexemes, which are words that have been normalized to
merge different variants of the same word."
**"A tsvector value is a sorted list of distinct lexemes, which are words that have been normalized to
merge different variants of the same word."**
from the PostgreSQL doc (http://www.postgresql.org/docs/9.0/interactive/datatype-textsearch.html#DATATYPE-TSVECTOR).
Thus tsvector skips all the fill words and reduces nouns to their single form, a behaviour useful
for searching texts. However as we are normally dealing with place names here we want them to stay as they are.
If you use a language where the single form is a lot different from the plural form but your name contains a plural
you will not get a suitable result. If you want to use the tsvector search option you should activate the lines

::

sql += "searchstring_tsvector @@ to_tsquery(\'not_your_language\', %s)"
data += (querystrings[j]+":*",)

not_your_language is to be replaced with an entry e.g. finnish if you have German place names.
Thus plural forms and fillwords are kept as they are. Be aware of side effects!
Be sure to fill the field searchstring_tsvector with `to_tsvector('not_your_language', 'yourstring')`.
Be sure to fill the field searchstring_tsvector with ``to_tsvector('not_your_language', 'yourstring')``.

The use of

::

sql += "searchstring::tsvector @@ lower(%s)::tsquery"
data += (querystrings[j]+":*",)

Expand All @@ -790,15 +801,26 @@ is discouraged as it does not find a place name like Stoke-sub-Hamden when you e
If you do not want to use tsvector at all you can enable the full string comparison on the field searchstring
(activated by default).

::

sql += "searchstring ILIKE %s"
data += ("%" + querystrings[j] + "%",)

This method however is slower than tsvector but not relevantly at least if you only have a couple 1000 datasets.


6.2.3. PostgreSQL table setup for searching
6.2.3. PostgreSQL table setup for searching
===========================================

Geometry must have set CRS code.
Check (must return <>0):
SELECT ST_Srid(geom) from [TABLE] LIMIT 1;

Set (example, table name: admin, geometry column: geom, CRS to set:4326):
SELECT UpdateGeometrySRID('admin', 'geom', 4326);

::

CREATE TABLE cadastre.searchtable
(
searchstring text, --the search string (all lower case), e.g. "zürichstrasse 46, 8610 uster"
Expand All @@ -816,19 +838,19 @@ This method however is slower than tsvector but not relevantly at least if you o
OIDS=FALSE
);
GRANT SELECT ON TABLE cadastre.searchtable TO qwc_user;

-- Index: cadastre.in_cadastre_searchstring_tsvector_gin

CREATE INDEX in_cadastre_searchstring_tsvector_gin
ON cadastre.searchtable
USING gin
(searchstring_tsvector);

The above search table can also be a view or materialized view. One can combine
several search tables by specifying the `searchtables=searchtable1,searchtable_n`
parameter when requesting the search.wsgi script. Any searchtable passed to search.wsgi may only contain
the letters A to Z, a to z and the underscore. Double quoting the search table throws an error, thus searchtables' names must
contain lower characters only.
several search tables by specifying the ``searchtables=searchtable1,searchtable_n``
parameter when requesting the search.wsgi script. Any searchtable passed to ``search.wsgi``
may only contain the letters A to Z, a to z and the underscore. Double quoting the search
table throws an error, thus searchtables' names must contain lower characters only.

Using views is generally slower than properly indexed tables, check for yourself what works best.

Expand Down
78 changes: 69 additions & 9 deletions client/site/js/GeocodingSearchCombo.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ GeoExt.ux.GeocodingSearchCombo = Ext.extend(Ext.form.ComboBox, {
*/
map: null,

highlightLayerName: null,
highlightLayer: null,

/** api: config[width]
* See http://www.dev.sencha.com/deploy/dev/docs/source/BoxComponent.html#cfg-Ext.BoxComponent-width,
* default value is 350.
Expand Down Expand Up @@ -102,7 +105,7 @@ GeoExt.ux.GeocodingSearchCombo = Ext.extend(Ext.form.ComboBox, {
/** private: property[hideTrigger]
* Hide trigger of the combo.
*/
hideTrigger: true,
hideTrigger: false,

/** private: property[displayField]
* Display field name
Expand All @@ -127,8 +130,21 @@ GeoExt.ux.GeocodingSearchCombo = Ext.extend(Ext.form.ComboBox, {
/** private: constructor
*/
initComponent: function() {

this.triggerConfig = { // we use a default clear trigger here
tag: "img", src: Ext.BLANK_IMAGE_URL, cls:'x-form-trigger x-form-clear-trigger'
};
this.on("keyUp", this.keyUpHandler);
this.on("afterrender", this.afterrenderHandler);
this.on("beforeselect", this.beforeselectHandler);

GeoExt.ux.GeocodingSearchCombo.superclass.initComponent.apply(this, arguments);

//reference to highlightLayer
if (this.highlightLayerName) {
this.highlightLayer = this.map.getLayersByName(this.highlightLayerName)[0];
}

var params = {
"size": this.maxRows,
"layers": this.layers,
Expand All @@ -147,7 +163,9 @@ GeoExt.ux.GeocodingSearchCombo = Ext.extend(Ext.form.ComboBox, {
this.store = new Ext.data.Store({
proxy: new Ext.data.ScriptTagProxy({
url: this.url,
method: 'GET'
method: 'GET',
nocache: false,
autoAbort: true
}),
baseParams: params,
reader: new Ext.data.JsonReader({
Expand Down Expand Up @@ -214,24 +232,66 @@ GeoExt.ux.GeocodingSearchCombo = Ext.extend(Ext.form.ComboBox, {
{},
symbolizersHighLightLayer.Point
);
featureInfoHighlightLayer.removeAllFeatures();
featureInfoHighlightLayer.addFeatures(marker);
this.highlightLayer.removeAllFeatures();
this.highlightLayer.addFeatures(marker);

this.map.setCenter(position, this.zoom);
}, this);
}
},
getName2: function(v, record){
return record.properties.street + ' ' + record.properties.housenumber;
},

// private
afterrenderHandler: function() {
this.trigger["hide"]();
},

beforeselectHandler: function(combo,record,index) {
if (record.get('selectable') == "1") {
this.collapse();
}
},

keyUpHandler: function(cmp, e) {
//reset if user deleted last sign
this.checkTrigger();
if (Ext.isEmpty(this.getValue())) {
this.resetSearch();
}
//collapse if less than minChars are left
if (this.getValue().length < this.minChars) {
this.collapse();
}
},

checkTrigger: function() {
// show trigger only if there is any input
if (this.rendered) {
this.trigger[!Ext.isEmpty(this.getValue()) ? 'show': 'hide']();
}
},

onTriggerClick: function() {
// reimplements default onTriggerClick function (which does nothing)
this.resetSearch();
this.checkTrigger();
this.focus();
},

resetSearch: function(){
this.collapse();
this.clearSearchResult();
},

clearSearchResult: function() {
this.setValue("");
//TODO, FIX THIS
if (this.highlightLayer) {
this.highlightLayer.removeAllFeatures();
}
featureInfoHighlightLayer.removeAllFeatures();
},
getName2: function(v, record){
return record.properties.street + ' ' + record.properties.housenumber;
}

});

/** api: xtype = gxux_GeocodingSearchCombo */
Expand Down
2 changes: 1 addition & 1 deletion client/site/js/GetUrlParams.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var olBoundsRegexp = /^-*[\d\.]+,-*[\d\.]+,-*[\d\.]+,-*[\d\.]+$/; //regExp to ch
var urlString = "";
var format = "image/png"; //the default image format
var origFormat = format; //the original default image format, format is temporarily changed
var searchtables = null;
var searchtables = projectData.wsgi ? projectData.wsgi.searchtables : null;
var visibleLayers = null; //later an array of layer names that are initially visible
var visibleBackgroundLayer = null; // later the name of the visibleBackgroundLayer
var initialLayerOrder = null; //later an array containing the initialLayerOrder
Expand Down
4 changes: 2 additions & 2 deletions client/site/js/LoadAppProjectData.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ var elevationPrecision = 1; //precision of height in GetFeatureInfo result w
var minimumAddressRange = 1000; //range in meters within address is displayed with GetFeatureInfo, if outside than only regional info is displayed

//URL for custom search scripts
var searchBoxQueryURL = null; // "/wsgi/search.wsgi?query=";
var searchBoxGetGeomURL = null; // "/wsgi/getSearchGeom.wsgi";
var searchBoxQueryURL = projectData.wsgi ? "/wsgi/search.wsgi?query=" : null;
var searchBoxGetGeomURL = projectData.wsgi ? "/wsgi/getSearchGeom.wsgi" : null;

var autoActivateSearchGeometryLayer = true;

Expand Down
53 changes: 27 additions & 26 deletions client/site/js/QGISExtensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -645,35 +645,35 @@ QGIS.SearchComboBox = Ext.extend(Ext.form.ComboBox, {
* @param object record
* @param int index
*/
recordSelected: function(combo, record, index) {
recordSelected: function (combo, record, index) {
var bbox = record.get('bbox');

if (bbox != null) {
var extent = OpenLayers.Bounds.fromArray(bbox, this.hasReverseAxisOrder);

//make sure that map extent is not too small for point data
//need to improve this for units other than "m", e.g. degrees
//UROS NO POINT IN THIS!
// var extWidth = extent.getWidth();
// var extHeight = extent.getHeight();
// if (extWidth < 50) {
// centerX = extent.left + extWidth * 0.5;
// extent.left = centerX - 25;
// extent.right = centerX + 25;
// }
// else {
// extent.left -= extWidth * 0.05;
// extent.right += extWidth * 0.05;
// }
// if (extHeight < 50) {
// centerY = extent.bottom + extHeight * 0.5;
// extent.bottom = centerY - 25;
// extent.top = centerY + 25;
// }
// else {
// extent.bottom -= extHeight = 0.05;
// extent.top += extHeight = 0.05;
// }

var extWidth = extent.getWidth();
var extHeight = extent.getHeight();
if (extWidth < 50) {
centerX = extent.left + extWidth * 0.5;
extent.left = centerX - 25;
extent.right = centerX + 25;
}
else {
extent.left -= extWidth * 0.05;
extent.right += extWidth * 0.05;
}
if (extHeight < 50) {
centerY = extent.bottom + extHeight * 0.5;
extent.bottom = centerY - 25;
extent.top = centerY + 25;
}
else {
extent.bottom -= extHeight = 0.05;
extent.top += extHeight = 0.05;
}
//need to check if extent is too small
this.map.zoomToExtent(extent);
}
Expand All @@ -682,14 +682,14 @@ QGIS.SearchComboBox = Ext.extend(Ext.form.ComboBox, {
Ext.Ajax.request({
url: this.geomUrl,
success: this.showSearchGeometry,
failure: function ( result, request) {
Ext.MessageBox.alert(errMessageSearchComboNetworkRequestFailureTitleString[lang], errMessageSearchComboNetworkRequestFailureString+result.responseText);
failure: function (result, request) {
Ext.MessageBox.alert(errMessageSearchComboNetworkRequestFailureTitleString[lang], errMessageSearchComboNetworkRequestFailureString + result.responseText);
},
method: 'GET',
params: {
searchtable: record.get('searchtable'),
showlayer: record.get('showlayer'),
searchtext: record.get('searchtext'),
displaytext: record.get('displaytext'),
srs: this.srs
}
});
Expand All @@ -703,9 +703,10 @@ QGIS.SearchComboBox = Ext.extend(Ext.form.ComboBox, {
showSearchGeometry: function(result, request) {
// Check if we need to activate the layer and the layers exists...
var showLayerName = request.params.showlayer ? request.params.showlayer: request.params.searchtable;
var layerId = wmsLoader.layerTitleNameMapping[showLayerName];
if( typeof autoActivateSearchGeometryLayer != 'undefined'
&& autoActivateSearchGeometryLayer
&& allLayers.indexOf(showLayerName) != -1 )
&& allLayers.indexOf(layerId) != -1 )
{
var found = false;
layerTree.root.cascade(function(n){
Expand Down

0 comments on commit 4d4ddc1

Please sign in to comment.