diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index eb679fa..0000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "python.linting.pylintEnabled": true,
- "python.linting.enabled": true,
- "python.linting.pylintUseMinimalCheckers": false,
-}
\ No newline at end of file
diff --git a/french_address.py b/french_address.py
index 56c2013..a14a4d2 100644
--- a/french_address.py
+++ b/french_address.py
@@ -34,6 +34,7 @@
from .resources import *
from .french_address_dockwidget import FrenchAddressDockWidget
+from .french_address_widget_result_setting import FrenchAddressWidgetResultSetting
class FrenchAddress:
@@ -76,6 +77,7 @@ def __init__(self, iface):
#print "** INITIALIZING FrenchAddress"
self.pluginIsActive = False
self.dockwidget = None
+ self.widgetResultSetting = None
self.data_from_api = ""
self.tool = None
@@ -83,6 +85,7 @@ def __init__(self, iface):
self.catch_tool_icon = QgsApplication.iconPath("cursors/mCapturePoint.svg")
self.copy_icon = QgsApplication.iconPath("mActionEditCopy.svg")
self.show_url_icon = QgsApplication.iconPath("mIconWms.svg")
+ self.result_setting_icon = QgsApplication.iconPath("mActionOptions.svg")
self.clipboard = QApplication.clipboard()
# noinspection PyMethodMayBeStatic
@@ -190,7 +193,7 @@ def clear(self):
def enable_disable_catch_tool(self):
if not self.catch_tool_activate:
- self.tool = CatchTool(self.iface, self.dockwidget, self)
+ self.tool = CatchTool(self.iface, self.dockwidget, self.widgetResultSetting, self)
self.canvas.setMapTool(self.tool)
self.canvas.setCursor(QCursor(QPixmap(self.catch_tool_icon)))
self.catch_tool_activate = True
@@ -226,7 +229,7 @@ def address_processing(self):
response_coordinates = self.api_address.take_reverse_response_coordinates()
response_properties.update(response_coordinates)
self.api_address.populate_table_widget(response_properties)
- point_wgs84 = self.api_address.take_search_response_label()
+ point_wgs84 = self.api_address.take_search_response_coordinates()
self.coord.set_canvas_project(self.canvas)
self.coord.set_destination_crs()
self.coord.take_crs_from_project(self.iface)
@@ -234,7 +237,7 @@ def address_processing(self):
self.coord.set_latitude_longitude_crs(point_wgs84)
self.coord.zoom_to_canvas(self.canvas)
else:
- message = self.tr(' Format of the address is not correct, please check log message.')
+ message = ' Le format de l\'adresse est incorrecte'
self.iface.messageBar().pushMessage('Warning',
message,
level=Qgis.Warning,
@@ -249,11 +252,11 @@ def set_visible_properties(self, state):
def copy_to_clipboard(self):
text_to_copy = self.dockwidget.le_input_address.toPlainText()
- message = self.tr(' Nothing to copying')
+ message = ' Rien à copier'
if text_to_copy != '':
self.clipboard.setText(text_to_copy)
- message = self.tr(f' {text_to_copy}, copied to the clipboard')
+ message = f' {text_to_copy}, copié dans le presse papier'
self.iface.messageBar().pushMessage('Address',
message,
@@ -267,10 +270,10 @@ def open_map_url(self):
id_house = self.data_from_api['features'][0]['properties']['id']
url = self.api_address.set_map_url(longitude_house, latitude_house, id_house)
self.api_address.open_map_url(url)
- text = self.tr(' Open in web browser ')
+ text = ' Ouvert dans le navigateur '
message = text + f'{url}'
except:
- message = self.tr(' Nothing to open in web browser')
+ message = ' Rien à ouvrir dans le navigateur'
self.iface.messageBar().pushMessage('Address',
message,
@@ -293,6 +296,16 @@ def set_connections(self):
self.dockwidget.tb_open_url.clicked.connect(
self.open_map_url
)
+ self.dockwidget.tb_result_setting.clicked.connect(
+ self.show_result_setting
+ )
+
+ def show_result_setting(self):
+
+ if self.widgetResultSetting is None:
+ self.widgetResultSetting = FrenchAddressWidgetResultSetting()
+
+ self.widgetResultSetting.show()
def run(self):
"""Run method that loads and starts the plugin"""
@@ -302,6 +315,7 @@ def run(self):
if self.dockwidget is None:
self.dockwidget = FrenchAddressDockWidget()
+ self.widgetResultSetting = FrenchAddressWidgetResultSetting()
self.dockwidget.tw_details.setVisible(False)
self.coord = Coordinates(self.dockwidget)
self.address = Address(self.dockwidget)
@@ -309,6 +323,7 @@ def run(self):
self.dockwidget.tb_catch_tool.setIcon(QIcon(self.catch_tool_icon))
self.dockwidget.pb_copy.setIcon(QIcon(self.copy_icon))
self.dockwidget.tb_open_url.setIcon(QIcon(self.show_url_icon))
+ self.dockwidget.tb_result_setting.setIcon(QIcon(self.result_setting_icon))
self.set_connections()
self.dockwidget.closingPlugin.connect(self.onClosePlugin)
diff --git a/french_address_dockwidget_base.ui b/french_address_dockwidget_base.ui
index 7f9f8b9..edfcf90 100644
--- a/french_address_dockwidget_base.ui
+++ b/french_address_dockwidget_base.ui
@@ -7,7 +7,7 @@
0
0
422
- 368
+ 373
@@ -18,45 +18,20 @@
QLayout::SetMinAndMaxSize
- -
-
-
-
- 0
- 0
-
-
-
-
- 16777215
- 48
-
-
-
- false
-
-
- Qt::TextEditorInteraction
-
-
- Your address here, like 8 Boulevard du Port 80000
+
-
+
+
+
+ 8
+ true
+
-
-
- -
-
- Research
-
-
- true
-
-
- false
+ Résultat :
- -
+
-
@@ -71,7 +46,7 @@
- Click on the map to capture an address
+ Cliquer sur la carte pour capturer l'adresse
...
@@ -90,20 +65,7 @@
- -
-
-
-
- MS Shell Dlg 2
- 8
-
-
-
- Show more details
-
-
-
- -
+
-
@@ -113,7 +75,6 @@
- MS Shell Dlg 2
8
@@ -137,17 +98,42 @@
- attribute
+ attributs
- value
+ valeurs
- -
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 48
+
+
+
+ false
+
+
+ Qt::TextEditorInteraction
+
+
+ Votre adresse ici, comme 8 Boulevard du Port 80000
+
+
+
+ -
@@ -162,28 +148,39 @@
- Copy result to clipboard
+ Copier dans le presse papier
...
- -
-
+
-
+
+
+ Rechercher
+
+
+ true
+
+
+ false
+
+
+
+ -
+
8
- 75
- true
- Result:
+ Montrer plus de détails
- -
+
-
@@ -198,7 +195,29 @@
- Show address on website 'adresse.data.gouv.fr'
+ Montre l'adresse sur le site 'adresse.data.gouv.fr'
+
+
+ ...
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+ Paramètre résultat
...
diff --git a/french_address_result_setting.ui b/french_address_result_setting.ui
new file mode 100644
index 0000000..2198f6e
--- /dev/null
+++ b/french_address_result_setting.ui
@@ -0,0 +1,105 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 266
+ 158
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 266
+ 158
+
+
+
+
+ 266
+ 158
+
+
+
+ Paramètre résultat
+
+
+
+
+ 9
+ 51
+ 151
+ 20
+
+
+
+ postcode (code postale)
+
+
+
+
+
+ 9
+ 77
+ 141
+ 20
+
+
+
+ citycode (code INSEE)
+
+
+
+
+
+ 9
+ 103
+ 33
+ 20
+
+
+
+ id
+
+
+
+
+
+ 9
+ 129
+ 63
+ 20
+
+
+
+ context
+
+
+
+
+
+ 9
+ 9
+ 233
+ 32
+
+
+
+ Activé les éléments pour les faires apparaître dans la partie résultat.
+
+
+ true
+
+
+
+
+
+
diff --git a/french_address_widget_result_setting.py b/french_address_widget_result_setting.py
new file mode 100644
index 0000000..7ea80d1
--- /dev/null
+++ b/french_address_widget_result_setting.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+"""
+/***************************************************************************
+ FrenchAddressDockWidget
+ A QGIS plugin
+ Recherche et localisation d'adresse française.
+ Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
+ -------------------
+ begin : 2020-04-20
+ git sha : $Format:%H$
+ copyright : (C) 2020 by Guillaume DELPLANQUE
+ email : delpro.guillaume@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+"""
+
+import os
+
+from qgis.PyQt import QtGui, QtWidgets, uic
+from qgis.PyQt.QtCore import pyqtSignal
+
+FORM_CLASS, _ = uic.loadUiType(os.path.join(
+ os.path.dirname(__file__), 'french_address_result_setting.ui'))
+
+
+class FrenchAddressWidgetResultSetting(QtWidgets.QDockWidget, FORM_CLASS):
+
+ closingPlugin = pyqtSignal()
+
+ def __init__(self, parent=None):
+ """Constructor."""
+ super(FrenchAddressWidgetResultSetting, self).__init__(parent)
+ # Set up the user interface from Designer.
+ # After setupUI you can access any designer object by doing
+ # self., and you can use autoconnect slots - see
+ # http://doc.qt.io/qt-5/designer-using-a-ui-file.html
+ # #widgets-and-dialogs-with-auto-connect
+ self.setupUi(self)
+
+ def closeEvent(self, event):
+ self.closingPlugin.emit()
+ event.accept()
diff --git a/i18n/FrenchAddress_fr.qm b/i18n/FrenchAddress_fr.qm
deleted file mode 100644
index 3678efc..0000000
Binary files a/i18n/FrenchAddress_fr.qm and /dev/null differ
diff --git a/i18n/FrenchAddress_fr.ts b/i18n/FrenchAddress_fr.ts
deleted file mode 100644
index 62445a1..0000000
--- a/i18n/FrenchAddress_fr.ts
+++ /dev/null
@@ -1,298 +0,0 @@
-
-
-
-
- Address
-
-
-
- Le format de l'adresse n'est pas respecté
-
- exemple: 20 Avenue de Ségur 75007 Paris
-
-
-
-
- Vous avez besoin d'un numéro de maison
-
- exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Il manque un nom de rue
-
- exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Le code postal est manquant
-
- exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Le format de l'adresse n'est pas respecté
-
- exemple: 20 Avenue de Ségur 75007 Paris
-
-
-
-
- Vous avez besoin d'un numéro de maison
-
- exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Il manque un nom de rue
-
- exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Le code postal est manquant
-
- exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Le format de l'adresse n'est pas respecté
-
- exemple: 20 Avenue de Ségur 75007 Paris
-
-
-
-
- Vous avez besoin d'un numéro de maison
-
- exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Il manque un nom de rue
-
- exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Le code postal est manquant
-
- exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Le format de l'adresse n'est pas respecté exemple: 20 Avenue de Ségur 75007 Paris
-
-
-
-
- Vous avez besoin d'un numéro de maison exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Il manque un nom de rue exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Le code postal est manquant exemple: 20 Avenue de Ségur 75007
-
-
-
-
- L'adresse est complète
-
-
-
-
- Le format de l'adresse n'est pas respecté exemple: 20 Avenue de Ségur 75007 Paris
-
-
-
-
- Vous avez besoin d'un numéro de maison exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Il manque un nom de rue exemple: 20 Avenue de Ségur 75007
-
-
-
-
- Le code postal est manquant exemple: 20 Avenue de Ségur 75007
-
-
-
- ApiAddress
-
-
-
- Aucune adresse trouvée à ces coordonnées
-
-
-
-
- Il n'y a pas d'adresse avec c'est valeurs
-
-
-
-
- La connexion a échoué
-
-
-
-
- Connection établie
-
-
-
-
- attribut
-
-
-
-
- valeur
-
-
-
- CatchTool
-
-
-
- aucune adresse trouvée à ces coordonnées
-
-
-
-
- cliquer sur la carte pour capturer une adresse...
-
-
-
- FrenchAddress
-
-
-
- Le format de l'adresse n'est pas correct, veuillez vérifier le message du journal.
-
-
-
-
- Rien à copier
-
-
-
-
- Rien à ouvrir dans le navigateur Web
-
-
-
-
- Ouvertr dans le navigateur Web
-
-
-
- FrenchAddressDockWidgetBase
-
-
-
- French Address
-
-
-
-
- Votre adresse ici, exemple 8 Boulevard du Port 80000
-
-
-
-
- Chercher
-
-
-
-
- Cliquez sur la carte pour capturer une adresse
-
-
-
-
- ...
-
-
-
-
- Afficher plus de détails
-
-
-
-
- attribut
-
-
-
-
- valeur
-
-
-
-
- Copier le résultat dans le presse-papiers
-
-
-
-
- Copy to clipboard
- ...
-
-
-
-
- Résultat:
-
-
-
-
- Afficher l'adresse sur le site 'adresse.data.gouv.fr'
-
-
-
-
- Rechercher
-
-
-
diff --git a/metadata.txt b/metadata.txt
index c7dfec4..7e5201b 100644
--- a/metadata.txt
+++ b/metadata.txt
@@ -7,18 +7,18 @@ name=French Address
qgisMinimumVersion=3.4
description=Research and location based on the API BAN provided by the French government .
description[fr]=Recherche et localisation basées sur l'API BAN fournie par le gouvernement français.
-version=1.2
+version=1.3.0
author=Guillaume DELPLANQUE
email=delpro.guillaume@gmail.com
about=For research an address, simply write the desired address in the plugin's research bar.
For best results, enter a house number, street name, and zip code.
You can also retrieve the address based on the coordinates by activating the tool "Click on the map to capture an address".
- The cursor will change to a cross and you can start typing.
+ The cursor will change to a cross and you can start catching.
about[fr]=Pour rechercher une adresse, il suffit d'écrire l'adresse souhaitée dans la barre de recherche du plugin.
Pour de meilleurs résultats, entrez un numéro de maison, un nom de rue et le code postal.
- Vous pouvez également récupérez l'adresse en fonction des coordonnées en activant l'outil' "Cliquez sur la carte pour capturer une adresse".
- Le curseur se changera en croix et vous pourrez commencer la saisie.
+ Vous pouvez également récupérez l'adresse en fonction des coordonnées en activant l'outil' "Cliquez sur la carte pour capturer l'adresse".
+ Le curseur se changera en croix et vous pourrez commencer la capture.
tracker=https://github.com/Gui0delp/french_address/issues
repository=https://github.com/Gui0delp/french_address
@@ -28,10 +28,15 @@ repository=https://github.com/Gui0delp/french_address
hasProcessingProvider=no
# Uncomment the following line and add your changelog:
-changelog=1.2
+changelog=1.3.0
+ - added setting panel for choose result format
+ 1.2.0
+ - refact api address module
+ - add network access manager by Alessandro Pasotti
+ 1.1.1
- fix bug when deactivate the catch tool
- updated translate file for French language
- 1.1
+ 1.1.0
- now you can view more details from result
- redesign of the capture tool
- add tool to show address on the web browser
diff --git a/modules/address.py b/modules/address.py
index 8b1f42a..76a3629 100644
--- a/modules/address.py
+++ b/modules/address.py
@@ -29,7 +29,7 @@ def test_address_entry(self, entry):
self.entry = re.match(self.pattern_address, str(entry))
flag = True
else:
- self.message_log(self.tr('The address format is not respected example: 20 Avenue de Ségur 75007 Paris'))
+ self.message_log("Le format de l'adresse n'ai pas respecté, exemple: 20 Avenue de Ségur 75007 Paris")
flag = False
return flag
@@ -45,18 +45,18 @@ def test_obligatory_field(self):
test = True
if not self.house_number:
test = False
- self.message_log(self.tr('You need a house number example: 20 Avenue de Ségur 75007'))
+ self.message_log("Vous devez avoir un numéro de rue, exemple: 20 Avenue de Ségur 75007")
if not self.name_road:
test = False
- self.message_log(self.tr('Missing a street name example: 20 Avenue de Ségur 75007'))
+ self.message_log("Il manque un nom de rue, exemple: 20 Avenue de Ségur 75007")
if not self.postcode:
test = False
- self.message_log(self.tr('The postal code is missing example: 20 Avenue de Ségur 75007'))
+ self.message_log("Le code postal est manquant, exemple: 20 Avenue de Ségur 75007")
if test:
- self.message_log(self.tr('Address is complete'))
+ self.message_log("Adresse complète")
return test
def message_log(self, msg=""):
diff --git a/modules/api_address.py b/modules/api_address.py
index 99900b5..b33239a 100644
--- a/modules/api_address.py
+++ b/modules/api_address.py
@@ -10,6 +10,8 @@
from PyQt5.Qt import QApplication, QUrl, QDesktopServices
from qgis.PyQt.QtCore import QTranslator, QCoreApplication
+from .networkaccessmanager import NetworkAccessManager, RequestsException
+
class ApiAddress:
""" This class manage the methods for api
@@ -18,13 +20,15 @@ class ApiAddress:
def __init__(self, dialog=None):
self.dialog = dialog
self.zoom_to_map = 19
- self.reverse_url = "https://api-adresse.data.gouv.fr/reverse/"
- self.search_url = "https://api-adresse.data.gouv.fr/search/"
- self.map_url = "https://adresse.data.gouv.fr/base-adresse-nationale/"
+ self.REVERSE_URL = "https://api-adresse.data.gouv.fr/reverse/"
+ self.SEARCH_URL = "https://api-adresse.data.gouv.fr/search/"
+ self.MAP_URL = "https://adresse.data.gouv.fr/base-adresse-nationale/"
+ self.USER_AGENT = b'Mozilla/5.0 QGIS LocatorFilter'
+ self.headers = {b'User-Agent': self.USER_AGENT}
self.url = ""
- self.response = ""
+ self.content = ""
self.json_data = ""
- self.search_label = ""
+ self.search_coordinates = ""
self.my_context = ssl._create_unverified_context()
self.latitude = ""
self.longitude = ""
@@ -33,10 +37,12 @@ def __init__(self, dialog=None):
self.reverse_properties = {}
self.reverse_coordinates = {}
- self.error_message_no_address_locate = self.tr("No address found at this coordinates")
- self.error_message_no_address_found = self.tr("There is no address with this entry")
- self.error_message_connection = self.tr('The connection failed')
- self.success_message_connection = self.tr('Connection established')
+ self.nam = NetworkAccessManager()
+
+ self.error_message_no_address_locate = "Pas d'adresse trouvé avec ces coordonnées"
+ self.error_message_no_address_found = "Pas d'adresse avec ces critères"
+ self.error_message_connection = "La connexion a échouée"
+ self.success_message_connection = "Connexion établie"
def tr(self, message):
return QCoreApplication.translate('FrenchAddress', message)
@@ -45,7 +51,7 @@ def set_reverse_url(self, longitude, latitude):
"""Set the reverse url with the longitude and latitude"""
lon = str(longitude)
lat = str(latitude)
- self.url = self.reverse_url + '?lon=' + lon + '&lat=' + lat
+ self.url = self.REVERSE_URL + '?lon=' + lon + '&lat=' + lat
return self.url
def set_map_url(self, longitude_house, latitude_house, id_house):
@@ -53,7 +59,7 @@ def set_map_url(self, longitude_house, latitude_house, id_house):
lon = str(longitude_house)
lat = str(latitude_house)
id = id_house
- url_for_map = self.map_url + str(id) + '#' + str(self.zoom_to_map) + '/' + lat + '/' + lon
+ url_for_map = self.MAP_URL + str(id) + '#' + str(self.zoom_to_map) + '/' + lat + '/' + lon
return url_for_map
def open_map_url(self, url_for_map):
@@ -63,7 +69,9 @@ def open_map_url(self, url_for_map):
def test_request(self):
"""test if the request is OK"""
try:
- urlopen(self.url, context=self.my_context)
+ headers = {b'User-Agent': self.USER_AGENT}
+ (response, content) = self.nam.request(self.url, headers=headers, blocking=True)
+ #urlopen(self.url, context=self.my_context)
self.message_log(f'{self.success_message_connection}: {self.url}')
return True
except:
@@ -72,12 +80,14 @@ def test_request(self):
def set_request(self):
"""Open the url"""
- self.response = urlopen(self.url, context=self.my_context)
- return self.response
+ headers = {b'User-Agent': self.USER_AGENT}
+ (response, content) = self.nam.request(self.url, headers=headers, blocking=True)
+ self.content = content
+ return self.content
def decode_response(self):
"""decode with the utf-8 encodage, the response"""
- self.json_data = self.response.read().decode('utf-8')
+ self.json_data = self.content.decode('utf-8')
return self.json_data
def json_to_dictionnary(self):
@@ -120,7 +130,7 @@ def set_search_url(self, house_number, name_road, post_code):
name_parse = urllib.parse.quote(name_road, safe='\'')
- self.url = self.search_url \
+ self.url = self.SEARCH_URL \
+ '?q=' + house_number \
+ '%20' + name_parse \
+ post_code \
@@ -128,22 +138,21 @@ def set_search_url(self, house_number, name_road, post_code):
+ '&autocomplete=1'
return self.url
- def take_search_response_label(self):
- """Return the label of the request"""
+ def take_search_response_coordinates(self):
+ """Return the coordinates of the request"""
try:
- self.search_label = \
- self.dictionnary_data['features'][0]['geometry']['coordinates']
+ self.search_coordinates = self.dictionnary_data['features'][0]['geometry']['coordinates']
except:
self.message_log(self.error_message_no_address_found)
- return self.search_label
+ return self.search_coordinates
def initialize_table_widget(self):
self.dialog.tw_details.clear()
self.dialog.tw_details.setRowCount(0)
self.dialog.tw_details.setColumnCount(2)
- head_attribute = self.tr("attribute")
- head_value = self.tr("value")
+ head_attribute = "attributs"
+ head_value = "valeurs"
self.dialog.tw_details.setHorizontalHeaderItem(0, QTableWidgetItem(head_attribute))
self.dialog.tw_details.setHorizontalHeaderItem(1, QTableWidgetItem(head_value))
diff --git a/modules/catch_tool.py b/modules/catch_tool.py
index 33299b4..0c1ebf2 100644
--- a/modules/catch_tool.py
+++ b/modules/catch_tool.py
@@ -1,24 +1,21 @@
"""Manage the tool"""
from qgis.gui import QgsMapTool
from qgis.core import Qgis, QgsMessageLog
-from qgis.PyQt.QtCore import QTranslator, QCoreApplication
from .coordinates import Coordinates
from .api_address import ApiAddress
class CatchTool(QgsMapTool):
- def __init__(self, iface, dialog, fr_address_instance):
+ def __init__(self, iface, dialog, setting_widget, fr_address_instance):
QgsMapTool.__init__(self, iface.mapCanvas())
self.canvas = iface.mapCanvas()
self.iface = iface
self.dialog = dialog
+ self.setting_widget = setting_widget
self.fr_address_instance = fr_address_instance
self.coord = Coordinates(self.dialog)
self.api_address = ApiAddress(self.dialog)
- def tr(self, message):
- return QCoreApplication.translate('FrenchAddress', message)
-
def canvasReleaseEvent(self, event):
x = event.pos().x()
y = event.pos().y()
@@ -41,10 +38,11 @@ def canvasReleaseEvent(self, event):
response_properties = self.api_address.take_reverse_response_properties()
response_coordinates = self.api_address.take_reverse_response_coordinates()
response_properties.update(response_coordinates)
- self.dialog.le_input_address.setText(response_label)
+ response = self.choose_results(response_label, response_properties)
+ self.dialog.le_input_address.setText(response)
self.api_address.populate_table_widget(response_properties)
else:
- message = self.tr(' no address found at this coordinates ')
+ message = " pas d'adresse trouvé avec ces coordonnées"
message_error = message + f'EPSG:4326 lon,lat = {self.coord.longitude},{self.coord.latitude}'
self.message_log(message_error)
self.iface.messageBar().pushMessage('Warning',
@@ -53,7 +51,7 @@ def canvasReleaseEvent(self, event):
)
def activate(self):
- message = self.tr(' click on the map to capture an address...')
+ message = " cliquer sur la carte pour capturer l'adresse..."
self.iface.messageBar().pushMessage('Info',
message,
level=Qgis.Info,
@@ -68,5 +66,22 @@ def deactivate(self):
self.fr_address_instance.catch_tool_activate = False
self.deactivated.emit()
+ def choose_results(self, response_label, response_properties):
+ response = response_label
+
+ if self.setting_widget.cbox_postcode.isChecked():
+ response = response + ' ' + response_properties['postcode']
+
+ if self.setting_widget.cbox_citycode.isChecked():
+ response = response + ' ' + response_properties['citycode']
+
+ if self.setting_widget.cbox_id.isChecked():
+ response = response + ' ' + response_properties['id']
+
+ if self.setting_widget.cbox_type.isChecked():
+ response = response + ' ' + response_properties['context']
+
+ return response
+
def message_log(self, msg=""):
QgsMessageLog.logMessage('{} {}'.format(self.__class__.__name__, msg), 'FrenchAddress', Qgis.Info)
diff --git a/modules/networkaccessmanager.py b/modules/networkaccessmanager.py
new file mode 100644
index 0000000..a8426a4
--- /dev/null
+++ b/modules/networkaccessmanager.py
@@ -0,0 +1,385 @@
+# -*- coding: utf-8 -*-
+"""
+***************************************************************************
+ An httplib2 replacement that uses QgsNetworkAccessManager
+
+ https://github.com/boundlessgeo/lib-qgis-commons/blob/master/qgiscommons2/network/networkaccessmanager.py
+
+ ---------------------
+ Date : August 2016
+ Copyright : (C) 2016 Boundless, http://boundlessgeo.com
+ Email : apasotti at boundlessgeo dot com
+***************************************************************************
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+***************************************************************************
+"""
+from future import standard_library
+standard_library.install_aliases()
+from builtins import str
+from builtins import object
+
+__author__ = 'Alessandro Pasotti'
+__date__ = 'August 2016'
+
+import re
+import urllib.request, urllib.error, urllib.parse
+
+from qgis.PyQt.QtCore import pyqtSlot, QUrl, QEventLoop, QTimer, QCoreApplication, QObject
+from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply
+
+from qgis.core import QgsNetworkAccessManager, QgsAuthManager, QgsMessageLog
+
+# FIXME: ignored
+DEFAULT_MAX_REDIRECTS = 4
+
+class RequestsException(Exception):
+ pass
+
+class RequestsExceptionTimeout(RequestsException):
+ pass
+
+class RequestsExceptionConnectionError(RequestsException):
+ pass
+
+class RequestsExceptionUserAbort(RequestsException):
+ pass
+
+class Map(dict):
+ """
+ Example:
+ m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
+ """
+ def __init__(self, *args, **kwargs):
+ super(Map, self).__init__(*args, **kwargs)
+ for arg in args:
+ if isinstance(arg, dict):
+ for k, v in arg.items():
+ self[k] = v
+
+ if kwargs:
+ for k, v in kwargs.items():
+ self[k] = v
+
+ def __getattr__(self, attr):
+ return self.get(attr)
+
+ def __setattr__(self, key, value):
+ self.__setitem__(key, value)
+
+ def __setitem__(self, key, value):
+ super(Map, self).__setitem__(key, value)
+ self.__dict__.update({key: value})
+
+ def __delattr__(self, item):
+ self.__delitem__(item)
+
+ def __delitem__(self, key):
+ super(Map, self).__delitem__(key)
+ del self.__dict__[key]
+
+
+class Response(Map):
+ pass
+
+class NetworkAccessManager(object):
+ """
+ This class mimicks httplib2 by using QgsNetworkAccessManager for all
+ network calls.
+ The return value is a tuple of (response, content), the first being and
+ instance of the Response class, the second being a string that contains
+ the response entity body.
+ Parameters
+ ----------
+ debug : bool
+ verbose logging if True
+ exception_class : Exception
+ Custom exception class
+ Usage 1 (blocking mode)
+ -----
+ ::
+ nam = NetworkAccessManager(authcgf)
+ try:
+ (response, content) = nam.request('http://www.example.com')
+ except RequestsException as e:
+ # Handle exception
+ pass
+ Usage 2 (Non blocking mode)
+ -------------------------
+ ::
+ NOTE! if blocking mode returns immediatly
+ it's up to the caller to manage listeners in case
+ of non blocking mode
+ nam = NetworkAccessManager(authcgf)
+ try:
+ nam.request('http://www.example.com', blocking=False)
+ nam.reply.finished.connect(a_signal_listener)
+ except RequestsException as e:
+ # Handle exception
+ pass
+ Get response using method:
+ nam.httpResult() that return a dictionary with keys:
+ 'status' - http code result come from reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
+ 'status_code' - http code result come from reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
+ 'status_message' - reply message string from reply.attribute(QNetworkRequest.HttpReasonPhraseAttribute)
+ 'content' - bytearray returned from reply
+ 'ok' - request success [True, False]
+ 'headers' - Dicionary containing the reply header
+ 'reason' - fomatted message string with reply.errorString()
+ 'exception' - the exception returne dduring execution
+ """
+
+ def __init__(self, authid=None, disable_ssl_certificate_validation=False, exception_class=None, debug=False):
+ self.disable_ssl_certificate_validation = disable_ssl_certificate_validation
+ self.authid = authid
+ self.reply = None
+ self.debug = debug
+ self.exception_class = exception_class
+ self.on_abort = False
+ self.blocking_mode = False
+ self.http_call_result = Response({
+ 'status': 0,
+ 'status_code': 0,
+ 'status_message': '',
+ 'content': '',
+ 'ok': False,
+ 'headers': {},
+ 'reason': '',
+ 'exception': None,
+ })
+
+ def msg_log(self, msg):
+ if self.debug:
+ QgsMessageLog.logMessage(msg, "NetworkAccessManager")
+
+ def httpResult(self):
+ return self.http_call_result
+
+ def request(self, url, method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS,
+ connection_type=None, blocking=True):
+ """
+ Make a network request by calling QgsNetworkAccessManager.
+ redirections argument is ignored and is here only for httplib2 compatibility.
+ """
+ self.msg_log(u'http_call request: {0}'.format(url))
+
+ self.blocking_mode = blocking
+ req = QNetworkRequest()
+ # Avoid double quoting form QUrl
+ url = urllib.parse.unquote(url)
+ req.setUrl(QUrl(url))
+ if headers is not None:
+ # This fixes a wierd error with compressed content not being correctly
+ # inflated.
+ # If you set the header on the QNetworkRequest you are basically telling
+ # QNetworkAccessManager "I know what I'm doing, please don't do any content
+ # encoding processing".
+ # See: https://bugs.webkit.org/show_bug.cgi?id=63696#c1
+ try:
+ del headers['Accept-Encoding']
+ except KeyError:
+ pass
+ for k, v in list(headers.items()):
+ self.msg_log("Setting header %s to %s" % (k, v))
+ req.setRawHeader(k, v)
+ if self.authid:
+ self.msg_log("Update request w/ authid: {0}".format(self.authid))
+ QgsAuthManager.instance().updateNetworkRequest(req, self.authid)
+ if self.reply is not None and self.reply.isRunning():
+ self.reply.close()
+ if method.lower() == 'delete':
+ func = getattr(QgsNetworkAccessManager.instance(), 'deleteResource')
+ else:
+ func = getattr(QgsNetworkAccessManager.instance(), method.lower())
+ # Calling the server ...
+ # Let's log the whole call for debugging purposes:
+ self.msg_log("Sending %s request to %s" % (method.upper(), req.url().toString()))
+ self.on_abort = False
+ headers = {str(h): str(req.rawHeader(h)) for h in req.rawHeaderList()}
+ for k, v in list(headers.items()):
+ self.msg_log("%s: %s" % (k, v))
+ if method.lower() in ['post', 'put']:
+ if isinstance(body, file):
+ body = body.read()
+ self.reply = func(req, body)
+ else:
+ self.reply = func(req)
+ if self.authid:
+ self.msg_log("Update reply w/ authid: {0}".format(self.authid))
+ QgsAuthManager.instance().updateNetworkReply(self.reply, self.authid)
+
+ # necessary to trap local timout manage by QgsNetworkAccessManager
+ # calling QgsNetworkAccessManager::abortRequest
+ QgsNetworkAccessManager.instance().requestTimedOut.connect(self.requestTimedOut)
+
+ self.reply.sslErrors.connect(self.sslErrors)
+ self.reply.finished.connect(self.replyFinished)
+ self.reply.downloadProgress.connect(self.downloadProgress)
+
+ # block if blocking mode otherwise return immediatly
+ # it's up to the caller to manage listeners in case of no blocking mode
+ if not self.blocking_mode:
+ return (None, None)
+
+ # Call and block
+ self.el = QEventLoop()
+ self.reply.finished.connect(self.el.quit)
+
+ # Catch all exceptions (and clean up requests)
+ try:
+ self.el.exec_(QEventLoop.ExcludeUserInputEvents)
+ except Exception as e:
+ raise e
+
+ if self.reply:
+ self.reply.finished.disconnect(self.el.quit)
+
+ # emit exception in case of error
+ if not self.http_call_result.ok:
+ if self.http_call_result.exception and not self.exception_class:
+ raise self.http_call_result.exception
+ else:
+ raise self.exception_class(self.http_call_result.reason)
+
+ return (self.http_call_result, self.http_call_result.content)
+
+ #@pyqtSlot()
+ def downloadProgress(self, bytesReceived, bytesTotal):
+ """Keep track of the download progress"""
+ #self.msg_log("downloadProgress %s of %s ..." % (bytesReceived, bytesTotal))
+ pass
+
+ #@pyqtSlot(QNetworkReply)
+ def requestTimedOut(self, QNetworkReply):
+ """Trap the timeout. In Async mode requestTimedOut is called after replyFinished"""
+ # adapt http_call_result basing on receiving qgs timer timout signal
+ self.exception_class = RequestsExceptionTimeout
+ self.http_call_result.exception = RequestsExceptionTimeout("Timeout error")
+
+ #@pyqtSlot(QObject)
+ def replyFinished(self):
+ err = self.reply.error()
+ httpStatus = self.reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
+ httpStatusMessage = self.reply.attribute(QNetworkRequest.HttpReasonPhraseAttribute)
+ self.http_call_result.status_code = httpStatus
+ self.http_call_result.status = httpStatus
+ self.http_call_result.status_message = httpStatusMessage
+ for k, v in self.reply.rawHeaderPairs():
+ self.http_call_result.headers[str(k)] = str(v)
+ self.http_call_result.headers[str(k).lower()] = str(v)
+
+ if err != QNetworkReply.NoError:
+ # handle error
+ # check if errorString is empty, if so, then set err string as
+ # reply dump
+ if re.match('(.)*server replied: $', self.reply.errorString()):
+ errString = self.reply.errorString() + self.http_call_result.content
+ else:
+ errString = self.reply.errorString()
+ # check if self.http_call_result.status_code is available (client abort
+ # does not produce http.status_code)
+ if self.http_call_result.status_code:
+ msg = "Network error #{0}: {1}".format(
+ self.http_call_result.status_code, errString)
+ else:
+ msg = "Network error: {0}".format(errString)
+
+ self.http_call_result.reason = msg
+ self.http_call_result.ok = False
+ self.msg_log(msg)
+ # set return exception
+ if err == QNetworkReply.TimeoutError:
+ self.http_call_result.exception = RequestsExceptionTimeout(msg)
+
+ elif err == QNetworkReply.ConnectionRefusedError:
+ self.http_call_result.exception = RequestsExceptionConnectionError(msg)
+
+ elif err == QNetworkReply.OperationCanceledError:
+ # request abort by calling NAM.abort() => cancelled by the user
+ if self.on_abort:
+ self.http_call_result.exception = RequestsExceptionUserAbort(msg)
+ else:
+ self.http_call_result.exception = RequestsException(msg)
+
+ else:
+ self.http_call_result.exception = RequestsException(msg)
+
+ # overload exception to the custom exception if available
+ if self.exception_class:
+ self.http_call_result.exception = self.exception_class(msg)
+
+ else:
+ # Handle redirections
+ redirectionUrl = self.reply.attribute(QNetworkRequest.RedirectionTargetAttribute)
+ if redirectionUrl is not None and redirectionUrl != self.reply.url():
+ if redirectionUrl.isRelative():
+ redirectionUrl = self.reply.url().resolved(redirectionUrl)
+
+ msg = "Redirected from '{}' to '{}'".format(
+ self.reply.url().toString(), redirectionUrl.toString())
+ self.msg_log(msg)
+
+ self.reply.deleteLater()
+ self.reply = None
+ self.request(redirectionUrl.toString())
+
+ # really end request
+ else:
+ msg = "Network success #{0}".format(self.reply.error())
+ self.http_call_result.reason = msg
+ self.msg_log(msg)
+
+ ba = self.reply.readAll()
+ self.http_call_result.content = bytes(ba)
+ self.http_call_result.ok = True
+
+ # Let's log the whole response for debugging purposes:
+ #self.msg_log("Got response %s %s from %s" % \
+ # (self.http_call_result.status_code,
+ # self.http_call_result.status_message,
+ # self.reply.url().toString()))
+ for k, v in list(self.http_call_result.headers.items()):
+ self.msg_log("%s: %s" % (k, v))
+ if len(self.http_call_result.content) < 1024:
+ self.msg_log("Payload :\n%s" % self.http_call_result.content)
+ else:
+ self.msg_log("Payload is > 1 KB ...")
+
+ # clean reply
+ if self.reply is not None:
+ if self.reply.isRunning():
+ self.reply.close()
+ self.msg_log("Deleting reply ...")
+ # Disconnect all slots
+ self.reply.sslErrors.disconnect(self.sslErrors)
+ self.reply.finished.disconnect(self.replyFinished)
+ self.reply.downloadProgress.disconnect(self.downloadProgress)
+ self.reply.deleteLater()
+ self.reply = None
+ else:
+ self.msg_log("Reply was already deleted ...")
+
+ #@pyqtSlot()
+ def sslErrors(self, ssl_errors):
+ """
+ Handle SSL errors, logging them if debug is on and ignoring them
+ if disable_ssl_certificate_validation is set.
+ """
+ if ssl_errors:
+ for v in ssl_errors:
+ self.msg_log("SSL Error: %s" % v.errorString())
+ if self.disable_ssl_certificate_validation:
+ self.reply.ignoreSslErrors()
+
+ #@pyqtSlot()
+ def abort(self):
+ """
+ Handle request to cancel HTTP call
+ """
+ if (self.reply and self.reply.isRunning()):
+ self.on_abort = True
+ self.reply.abort()
\ No newline at end of file