Ejemplo n.º 1
0
    def fetchResults(self, string, context, feedback):
        # collect results in main thread, since this method is inexpensive and
        # accessing the processing registry/current layer is not thread safe

        if iface.activeLayer() is None or iface.activeLayer().type() != QgsMapLayer.VectorLayer or not iface.activeLayer().selectedFeatureCount():
            return

        for a in QgsApplication.processingRegistry().algorithms():
            if not a.flags() & QgsProcessingAlgorithm.FlagSupportsInPlaceEdits:
                continue

            if not a.supportInPlaceEdit(iface.activeLayer()):
                continue

            if QgsLocatorFilter.stringMatches(a.displayName(), string) or [t for t in a.tags() if QgsLocatorFilter.stringMatches(t, string)] or \
                    (context.usingPrefix and not string):
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = a.displayName()
                result.icon = a.icon()
                result.userData = a.id()
                if string and QgsLocatorFilter.stringMatches(a.displayName(), string):
                    result.score = float(len(string)) / len(a.displayName())
                else:
                    result.score = 0
                self.resultFetched.emit(result)
Ejemplo n.º 2
0
    def fetchResults(self, string, context, feedback):
        for a in QgsApplication.processingRegistry().algorithms():
            if feedback.isCanceled():
                return
            if a.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox:
                continue

            if QgsLocatorFilter.stringMatches(a.displayName(), string) or [t for t in a.tags() if QgsLocatorFilter.stringMatches(t, string)]:
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = a.displayName()
                result.icon = a.icon()
                result.userData = a.id()
                if string and QgsLocatorFilter.stringMatches(a.displayName(), string):
                    result.score = float(len(string)) / len(a.displayName())
                else:
                    result.score = 0
                self.resultFetched.emit(result)
Ejemplo n.º 3
0
    def fetchResults(self, string, context, feedback):
        # collect results in main thread, since this method is inexpensive and
        # accessing the processing registry is not thread safe
        for a in QgsApplication.processingRegistry().algorithms():
            if a.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox:
                continue

            if QgsLocatorFilter.stringMatches(a.displayName(), string) or [t for t in a.tags() if QgsLocatorFilter.stringMatches(t, string)]:
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = a.displayName()
                result.icon = a.icon()
                result.userData = a.id()
                if string and QgsLocatorFilter.stringMatches(a.displayName(), string):
                    result.score = float(len(string)) / len(a.displayName())
                else:
                    result.score = 0
                self.resultFetched.emit(result)
    def fetchResults(self, search, context, feedback):

        if len(search) < 2:
            return

        # see https://operations.osmfoundation.org/policies/nominatim/
        # "Auto-complete search This is not yet supported by Nominatim and you must not implement such a service on the client side using the API."
        # so end with a space to trigger a search:
        if search[-1] != ' ':
            return

        url = '{}{}'.format(self.SEARCH_URL, search)
        self.info('Search url {}'.format(url))
        try:
            # see https://operations.osmfoundation.org/policies/nominatim/
            # "Pro4 vide a valid HTTP Referer or User-Agent identifying the application (QGIS geocoder)"
            # TODO
            #headers = {b'User-Agent': self.USER_AGENT}

            # nam = Network Access Manager
            nam = QgsBlockingNetworkRequest()
            request = QNetworkRequest(QUrl(url))
            request.setHeader(QNetworkRequest.UserAgentHeader, self.USER_AGENT)
            nam.get(request, forceRefresh=True)
            reply = nam.reply()
            if reply.attribute(
                    QNetworkRequest.HttpStatusCodeAttribute
            ) == 200:  # other codes are handled by NetworkAccessManager
                content_string = reply.content().data().decode('utf8')
                locations = json.loads(content_string)
                for loc in locations:
                    result = QgsLocatorResult()
                    result.filter = self
                    result.displayString = '{} ({})'.format(
                        loc['display_name'], loc['type'])
                    # use the json full item as userData, so all info is in it:
                    result.userData = loc
                    self.resultFetched.emit(result)

        except Exception as err:
            # Handle exception..
            # only this one seems to work
            self.info(err)
Ejemplo n.º 5
0
    def fetchResults(self, string, context, feedback):
        # collect results in main thread, since this method is inexpensive and
        # accessing the processing registry is not thread safe
        for a in QgsApplication.processingRegistry().algorithms():
            if a.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox:
                continue

            if QgsLocatorFilter.stringMatches(a.displayName(), string) or [t for t in a.tags() if QgsLocatorFilter.stringMatches(t, string)] or \
                    (context.usingPrefix and not string):
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = a.displayName()
                result.icon = a.icon()
                result.userData = a.id()
                if string and QgsLocatorFilter.stringMatches(a.displayName(), string):
                    result.score = float(len(string)) / len(a.displayName())
                else:
                    result.score = 0
                self.resultFetched.emit(result)
    def handle_response(self, response):
        try:
            if response.status_code != 200:
                if not isinstance(response.exception,
                                  RequestsExceptionUserAbort):
                    self.info(
                        "Error in main response with status code: {} from {}".
                        format(response.status_code, response.url))
                return

            data = json.loads(response.content.decode('utf-8'))
            # self.dbg_info(data)
            for loc in data['features']:
                importance = loc['properties']['importance']
                citycode = loc['properties']['citycode']
                score = loc['properties']['score']
                type_result = loc['properties']['type']
                label = loc['properties']['label']
                x = float(loc['geometry']['coordinates'][0])
                y = float(loc['geometry']['coordinates'][1])
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = label
                result.group = self.group_info(type_result)
                result.icon = QIcon(
                    ":/plugins/swiss_locator/icons/ban_locator.png")
                result.userData = LocationResult(importance, citycode, score,
                                                 type_result, label, x, y)
                self.result_found = True
                self.resultFetched.emit(result)

        except Exception as e:
            self.info(str(e), Qgis.Critical)
            exc_type, exc_obj, exc_traceback = sys.exc_info()
            filename = os.path.split(
                exc_traceback.tb_frame.f_code.co_filename)[1]
            self.info(
                '{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno),
                Qgis.Critical)
            self.info(
                traceback.print_exception(exc_type, exc_obj, exc_traceback),
                Qgis.Critical)
Ejemplo n.º 7
0
    def fetchResults(self, string, context, feedback):
        # collect results in main thread, since this method is inexpensive and
        # accessing the processing registry/current layer is not thread safe

        if iface.activeLayer() is None or iface.activeLayer().type() != QgsMapLayerType.VectorLayer:
            return

        for a in QgsApplication.processingRegistry().algorithms():
            if not a.flags() & QgsProcessingAlgorithm.FlagSupportsInPlaceEdits:
                continue

            if not a.supportInPlaceEdit(iface.activeLayer()):
                continue

            result = QgsLocatorResult()
            result.filter = self
            result.displayString = a.displayName()
            result.icon = a.icon()
            result.userData = a.id()
            result.score = 0

            if (context.usingPrefix and not string):
                self.resultFetched.emit(result)

            if not string:
                return

            string = string.lower()
            tagScore = 0
            tags = [*a.tags(), a.provider().name()]
            if a.group():
                tags.append(a.group())

            for t in tags:
                if string in t.lower():
                    tagScore = 1
                    break

            result.score = QgsStringUtils.fuzzyScore(result.displayString, string) * 0.5 + tagScore * 0.5

            if result.score > 0:
                self.resultFetched.emit(result)
Ejemplo n.º 8
0
    def fetchResults(self, search, context, feedback):
        key = self.settings.value(self.settings_key, defaultValue='', type=str, section=QgsSettings.Plugins)
        self.info('KEY: "{}" self: {}'.format(key, self))
        if key == '':
            result = QgsLocatorResult()
            result.filter = self
            result.displayString = self.displayName()
            self.resultFetched.emit(result)
            return

        if len(search) < 3:
            return

        search = search.strip()

        # Google places api
        # https://developers.google.com/places/web-service/query
        # https://developers.google.com/places/web-service/get-api-key
        # https://developers.google.com/places/web-service/usage  # 1000 requests per day
        url = 'https://maps.googleapis.com/maps/api/place/autocomplete/json?types=geocode&key={}&input={}'.format(key, search)

        try:
            self.info('{}'.format(url))
            (response, content) = self.nam.request(url)
            # TODO: check statuscode etc
            #  see https://developers.google.com/places/web-service/search#PlaceSearchResponses for Google status codes
            #self.info('{}'.format(response))
            content_string = content.decode('utf-8')
            obj = json.loads(content_string)

            docs = obj['predictions']
            for doc in docs:
                result = QgsLocatorResult()
                result.filter = self
                self.info('{}'.format(doc['description']))
                result.displayString = '{} ({})'.format(doc['description'], doc['types'])
                result.userData = doc
                self.resultFetched.emit(result)

        except RequestsException:
            # Handle exception
            print('!!!!!!!!!!! EXCEPTION !!!!!!!!!!!!!: \n{}'. format(RequestsException.args))
Ejemplo n.º 9
0
    def fetchResults(self, string, context, feedback):
        for a in QgsApplication.processingRegistry().algorithms():
            if feedback.isCanceled():
                return
            if a.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox:
                continue

            if QgsLocatorFilter.stringMatches(a.displayName(), string) or [
                    t for t in a.tags()
                    if QgsLocatorFilter.stringMatches(t, string)
            ]:
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = a.displayName()
                result.icon = a.icon()
                result.userData = a.id()
                if string and QgsLocatorFilter.stringMatches(
                        a.displayName(), string):
                    result.score = float(len(string)) / len(a.displayName())
                else:
                    result.score = 0
                self.resultFetched.emit(result)
Ejemplo n.º 10
0
    def fetchResults(self, search, context, feedback):

        if len(search) < 2:
            return

        url = '{}{}'.format(self.SEARCH_URL, search)
        self.info('Search url {}'.format(url))
        nam = NetworkAccessManager()
        try:

            headers = {b'User-Agent': self.USER_AGENT}
            # use BLOCKING request, as fetchResults already has it's own thread!
            (response, content) = nam.request(url,
                                              headers=headers,
                                              blocking=True)

            if response.status_code == 200:  # other codes are handled by NetworkAccessManager
                content_string = content.decode('utf-8')
                locations = json.loads(content_string)

                #loop on features in json collection
                for loc in locations['features']:

                    result = QgsLocatorResult()
                    result.filter = self
                    label = loc['properties']['label']
                    if loc['properties']['type'] == 'municipality':
                        # add city code to label
                        label += ' ' + loc['properties']['citycode']
                    result.displayString = '{} ({})'.format(
                        label, loc['properties']['type'])
                    #use the json full item as userData, so all info is in it:
                    result.userData = loc
                    self.resultFetched.emit(result)

        except RequestsException as err:
            # Handle exception..
            self.info(err)
            self.resultProblem.emit('{}'.format(err))
Ejemplo n.º 11
0
    def fetchResults(self, search, context, feedback):
        key = self.settings.value(self.settings_key, defaultValue='', type=str, section=QgsSettings.Plugins)
        # self.info('fetchResults KEY: "{}" self: {}'.format(key, self))
        if key == '':
            result = QgsLocatorResult()
            result.filter = self
            result.displayString = self.displayName()
            self.resultFetched.emit(result)
            return

        if len(search) < 3:
            return

        search = search.strip()

        # Google geocoding api
        # https://developers.google.com/maps/documentation/geocoding/get-api-key
        # https://developers.google.com/maps/documentation/geocoding/usage-limits  # 2500 requests per day
        url = 'https://maps.googleapis.com/maps/api/geocode/json?key={}&address={}'.format(key, search)

        try:
            self.info('{}'.format(url))
            (response, content) = self.nam.request(url)
            # TODO: check statuscode etc

            content_string = content.decode('utf-8')
            obj = json.loads(content_string)

            docs = obj['results']
            for doc in docs:
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = '{} ({})'.format(doc['formatted_address'], doc['types'])
                result.userData = doc
                self.resultFetched.emit(result)

        except networkaccessmanager.RequestsException:
            # Handle exception
            print('!!!!!!!!!!! EXCEPTION !!!!!!!!!!!!!: \n{}'. format(RequestsException.args))
Ejemplo n.º 12
0
    def fetch_result_single_database(self, search: str, connection_name: str):
        """ Fetch tables in the given database for a search. """
        connection = self.metadata.findConnection(connection_name)
        if not connection:
            self.logMessage(
                tr("The global variable {}_connection_name is not correct.").
                format(SCHEMA), Qgis.Critical)

        # Search items from pgmetadata.dataset
        sql = "  SELECT concat(d.title, ' (', d.table_name, '.', d.schema_name, ')') AS displayString,"
        sql += " d.schema_name, d.table_name, d.geometry_type, title"
        sql += " FROM pgmetadata.dataset d"
        sql += " INNER JOIN pgmetadata.v_valid_dataset v"
        sql += " ON concat(v.table_name, '.', v.schema_name) = concat(d.table_name, '.', d.schema_name)"
        sql += " WHERE concat(d.title, ' ', d.abstract, ' ', d.table_name) ILIKE '%{}%'".format(
            search)
        sql += " LIMIT 100"

        try:
            data = connection.executeSql(sql)
        except QgsProviderConnectionException as e:
            self.logMessage(str(e), Qgis.Critical)
            return

        if not data:
            return

        for item in data:
            result = QgsLocatorResult()
            result.filter = self
            result.displayString = item[0]
            result.icon = icon_for_geometry_type(item[3])
            result.userData = {
                'name': item[4],
                'connection': connection_name,
                'schema': item[1],
                'table': item[2],
            }
            self.resultFetched.emit(result)
Ejemplo n.º 13
0
    def fetchResults(self, string, context, feedback):
        # collect results in main thread, since this method is inexpensive and
        # accessing the processing registry is not thread safe
        for a in QgsApplication.processingRegistry().algorithms():
            if a.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox:
                continue
            if not ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES) and \
                    a.flags() & QgsProcessingAlgorithm.FlagKnownIssues:
                continue

            result = QgsLocatorResult()
            result.filter = self
            result.displayString = a.displayName()
            result.icon = a.icon()
            result.userData = a.id()
            result.score = 0

            if (context.usingPrefix and not string):
                self.resultFetched.emit(result)

            if not string:
                return

            string = string.lower()
            tagScore = 0
            tags = [*a.tags(), a.provider().name()]
            if a.group():
                tags.append(a.group())

            for t in tags:
                if string in t.lower():
                    tagScore = 1
                    break

            result.score = QgsStringUtils.fuzzyScore(
                result.displayString, string) * 0.5 + tagScore * 0.5

            if result.score > 0:
                self.resultFetched.emit(result)
Ejemplo n.º 14
0
    def fetchResults(self, search, context, feedback):
        ##print('--- PdokFilter fetchResults called')
        ##print('PdokFilter search: {}'.format(search))
        ##print('PdokFilter context: {}'.format(context))
        #print('PdokFilter context.targetExtent: {}'.format(context.targetExtent))
        #print('PdokFilter context.targetExtentCrs: {}'.format(context.targetExtentCrs))
        ##print('PdokFilter feedback: {}'.format(feedback))
        self.info(self.tr)
        if len(search) < 3:
            return

        # stripping the search string here to be able to see two geocoders at once and Nominatim needs a space on the end
        search = search.strip()
        url = 'https://geodata.nationaalgeoregister.nl/locatieserver/v3/suggest?q={}'.format(
            search)
        try:
            self.info('{}'.format(url))
            (response, content) = self.nam.request(url)
            ##print('response: {}'.format(response))
            # TODO: check statuscode etc
            ##print('content: {}'.format(content))

            content_string = content.decode('utf-8')
            obj = json.loads(content_string)
            docs = obj['response']['docs']
            for doc in docs:
                ##print(doc)
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = '{} ({})'.format(
                    doc['weergavenaam'], doc['type'])
                result.userData = doc
                self.resultFetched.emit(result)

        except RequestsException:
            # Handle exception
            print('!!!!!!!!!!! EXCEPTION !!!!!!!!!!!!!: \n{}'.format(
                RequestsException.args))
    def fetchResults(self, search, context, feedback):

        if len(search) < 2:
            return

        url = '{}{}'.format(self.SEARCH_URL, search)
        self.info('Search url {}'.format(url))
        nam = NetworkAccessManager()
        try:
            # "Provide a valid HTTP Referer or User-Agent identifying the application (QGIS geocoder)"
            headers = {b'User-Agent': self.USER_AGENT}
            # use BLOCKING request, as fetchResults already has it's own thread!
            (response, content) = nam.request(url,
                                              headers=headers,
                                              blocking=True)
            #self.info(response)
            #self.info(response.status_code)
            if response.status_code == 200:  # other codes are handled by NetworkAccessManager
                content_string = content.decode('utf-8')
                obj = json.loads(content_string)
                docs = obj['response']['docs']
                for doc in docs:
                    result = QgsLocatorResult()
                    result.filter = self
                    result.displayString = '{} ({})'.format(
                        doc['weergavenaam'], doc['type'])
                    # use the json full item as userData, so all info is in it:
                    result.userData = doc
                    self.resultFetched.emit(result)

        except RequestsException as err:
            # Handle exception..
            # only this one seems to work
            self.info(err)
            # THIS: results in a floating window with a warning in it, wrong thread/parent?
            #self.iface.messageBar().pushWarning("PDOKLocatieserverLocatorFilter Error", '{}'.format(err))
            # THIS: emitting the signal here does not work either?
            self.resultProblem.emit('{}'.format(err))
Ejemplo n.º 16
0
 def data_product_qgsresult(self, data: dict, sub_layer: bool, score: float,
                            stacktype) -> QgsLocatorResult:
     result = QgsLocatorResult()
     result.filter = self
     result.displayString = '{prefix}{title}'.format(
         prefix=' ↳ ' if sub_layer else '', title=data['display'])
     if stacktype == 'background':
         result.group = 'Karten (Hintergrundkarten)'
     else:
         result.group = 'Karten (Vordergrundkarten)'
     result.userData = DataProductResult(
         type=data['type'],
         dataproduct_id=data['dataproduct_id'],
         display=data['display'],
         dset_info=data['dset_info'],
         stacktype=stacktype,
         sublayers=data.get('sublayers', None))
     data_product = 'dataproduct'
     data_type = data['type']
     result.icon, result.description = dataproduct2icon_description(
         data_product, data_type)
     result.score = score
     return result
    def handle_response(self, response, content):
        try:
            if response.status_code != 200:
                self.info("Error with status code: {}".format(
                    response.status_code))
                return

            data = json.loads(content.decode('utf-8'))
            #self.dbg_info(data)

            features = data['features']
            for f in features:
                json_geom = json.dumps(f['geometry'])
                ogr_geom = ogr.CreateGeometryFromJson(json_geom)
                wkt = ogr_geom.ExportToWkt()
                geometry = QgsGeometry.fromWkt(wkt)
                self.dbg_info('---------')
                self.dbg_info(
                    QgsWkbTypes.geometryDisplayString(geometry.type()))
                self.dbg_info(f.keys())
                self.dbg_info('{} {}'.format(f['properties']['layer_name'],
                                             f['properties']['label']))
                self.dbg_info(f['bbox'])
                self.dbg_info(f['geometry'])
                if geometry is None:
                    continue
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = f['properties']['label']
                if Qgis.QGIS_VERSION_INT >= 30100:
                    result.group = self.beautify_group(
                        f['properties']['layer_name'])
                result.userData = geometry
                self.resultFetched.emit(result)

        except Exception as e:
            self.info(str(e), Qgis.Critical)
    def fetchResults(self, search: str, context: QgsLocatorContext,
                     feedback: QgsFeedback):
        try:
            self.dbg_info("start Swiss locator search...")

            if len(search) < 2:
                return

            if len(search) < 4 and self.type is FilterType.Feature:
                return

            self.result_found = False

            swisstopo_base_url = 'https://api3.geo.admin.ch/rest/services/api/SearchServer'
            swisstopo_base_params = {
                'type':
                self.type.value,
                'searchText':
                str(search),
                'returnGeometry':
                'true',
                'lang':
                self.lang,
                'sr':
                self.crs,
                'limit':
                str(
                    self.settings.value(
                        '{type}_limit'.format(type=self.type.value)))
                # bbox Must be provided if the searchText is not.
                # A comma separated list of 4 coordinates representing
                # the bounding box on which features should be filtered (SRID: 21781).
            }
            # Locations, WMS layers
            if self.type is not FilterType.Feature:
                nam = NetworkAccessManager()
                feedback.canceled.connect(nam.abort)

                search_urls = [(swisstopo_base_url, swisstopo_base_params)]

                if self.settings.value('layers_include_opendataswiss'
                                       ) and self.type is FilterType.WMS:
                    search_urls.append(
                        ('https://opendata.swiss/api/3/action/package_search?',
                         {
                             'q': 'q=WMS+%C3' + str(search)
                         }))

                for (swisstopo_base_url, swisstopo_base_params) in search_urls:
                    swisstopo_base_url = self.url_with_param(
                        swisstopo_base_url, swisstopo_base_params)
                    self.dbg_info(swisstopo_base_url)
                    try:
                        (response, content) = nam.request(swisstopo_base_url,
                                                          headers=self.HEADERS,
                                                          blocking=True)
                        self.handle_response(response, search, feedback)
                    except RequestsExceptionUserAbort:
                        pass
                    except RequestsException as err:
                        self.info(err)

            # Feature search
            else:
                # Feature search is split in several requests
                # otherwise URL is too long
                self.access_managers = {}
                try:
                    layers = list(self.searchable_layers.keys())
                    assert len(layers) > 0
                    step = 30
                    for l in range(0, len(layers), step):
                        last = min(l + step - 1, len(layers) - 1)
                        swisstopo_base_params['features'] = ','.join(
                            layers[l:last])
                        self.access_managers[self.url_with_param(
                            swisstopo_base_url, swisstopo_base_params)] = None
                except IOError:
                    self.info(
                        'Layers data file not found. Please report an issue.',
                        Qgis.Critical)

                # init event loop
                # wait for all requests to end
                self.event_loop = QEventLoop()

                def reply_finished(response):
                    self.handle_response(response, search, feedback)
                    if response.url in self.access_managers:
                        self.access_managers[response.url] = None
                    for nam in self.access_managers.values():
                        if nam is not None:
                            return
                        self.event_loop.quit()

                feedback.canceled.connect(self.event_loop.quit)

                # init the network access managers, create the URL
                for swisstopo_base_url in self.access_managers:
                    self.dbg_info(swisstopo_base_url)
                    nam = NetworkAccessManager()
                    self.access_managers[swisstopo_base_url] = nam
                    nam.finished.connect(reply_finished)
                    nam.request(swisstopo_base_url,
                                headers=self.HEADERS,
                                blocking=False)
                    feedback.canceled.connect(nam.abort)

                # Let the requests end and catch all exceptions (and clean up requests)
                if len(self.access_managers) > 0:
                    try:
                        self.event_loop.exec_(
                            QEventLoop.ExcludeUserInputEvents)
                    except RequestsExceptionUserAbort:
                        pass
                    except RequestsException as err:
                        self.info(str(err))

            if not self.result_found:
                result = QgsLocatorResult()
                result.filter = self
                result.displayString = self.tr('No result found.')
                result.userData = NoResult().as_definition()
                self.resultFetched.emit(result)

        except Exception as e:
            self.info(e, Qgis.Critical)
            exc_type, exc_obj, exc_traceback = sys.exc_info()
            filename = os.path.split(
                exc_traceback.tb_frame.f_code.co_filename)[1]
            self.info(
                '{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno),
                Qgis.Critical)
            self.info(
                traceback.print_exception(exc_type, exc_obj, exc_traceback),
                Qgis.Critical)
Ejemplo n.º 19
0
    def fetchResults(self, search, context, feedback):

        self.info('search {}'.format(search))

        if len(search) < 3:
            return

        if search in 'tomtom ':
            return

        project = QgsProject.instance()
        try:
            key = QgsExpressionContextUtils.projectScope(project).variable(
                'tomtom_api_key').strip()
        except:
            #QgsExpressionContextUtils.setProjectVariable(project, 'tomtom_api_key', '')
            self.info('Add tomtom_api_key variable to your project')
            key = ''
            return

        # End with a space to trigger a search:
        #if search[-1] != ' ':
        #    return

        url = '{}{}'.format(self.SEARCH_URL, search.strip())
        url = url + '.json?'
        url = url + '&key=' + key
        url = url + '&idxSet=POI,Geo,Addr,PAD,Str,Xstr'
        self.info('Search url {}'.format(url))
        nam = NetworkAccessManager()
        try:
            # use BLOCKING request, as fetchResults already has it's own thread!
            (response, content) = nam.request(url, blocking=True)
            #self.info(response)
            #self.info(response.status_code)
            if response.status_code == 200:  # other codes are handled by NetworkAccessManager
                content_string = content.decode('utf-8')
                locations = json.loads(content_string)
                for loc in locations['results']:
                    result = QgsLocatorResult()
                    result.filter = self
                    if loc['type'] == 'Geography':
                        loc_type = loc['entityType']
                    else:
                        loc_type = loc['type']

                    if loc['type'] == 'Geography':
                        loc_display = loc['address'][
                            'freeformAddress'] + ', ' + loc['address'][
                                'country']
                    elif loc['type'] == 'Street' or loc[
                            'type'] == 'Cross Street':
                        loc_display = loc['address']['streetName'] + ', ' + loc[
                            'address']['municipality'] + ', ' + loc['address'][
                                'country']
                    elif loc['type'] == 'POI':
                        if loc['poi'].get('brands'):
                            loc_display = loc['poi']['brands'][0][
                                'name'] + ' ' + loc['poi'][
                                    'name'] + ' - ' + loc['address'][
                                        'municipality'] + ', ' + loc[
                                            'address']['country']
                        else:
                            loc_display = loc['poi']['name'] + ' - ' + loc[
                                'address']['municipality'] + ', ' + loc[
                                    'address']['country']
                    else:
                        loc_display = loc['address'][
                            'freeformAddress'] + ', ' + loc['address'][
                                'country']

                    result.displayString = '{} ({})'.format(
                        loc_display, loc_type)
                    # use the json full item as userData, so all info is in it:
                    result.userData = loc
                    self.resultFetched.emit(result)

        except RequestsException as err:
            # Handle exception..
            # only this one seems to work
            self.info(err)
            # THIS: results in a floating window with a warning in it, wrong thread/parent?
            #self.iface.messageBar().pushWarning("TomTomLocatorFilter Error", '{}'.format(err))
            # THIS: emitting the signal here does not work either?
            self.resultProblem.emit('{}'.format(err))
    def handle_response(self, response):
        try:
            if response.status_code != 200:
                if not isinstance(response.exception, RequestsExceptionUserAbort):
                    self.info("Error in main response with status code: {} from {}"
                              .format(response.status_code, response.url))
                return

            data = json.loads(response.content.decode('utf-8'))
            # self.dbg_info(data)

            for loc in data['results']:
                self.dbg_info("keys: {}".format(loc['attrs'].keys()))
                if loc['attrs']['origin'] == 'layer':
                    # available keys: ['origin', 'lang', 'layer', 'staging', 'title', 'topics', 'detail', 'label', 'id']
                    for key, val in loc['attrs'].items():
                        self.dbg_info('{}: {}'.format(key, val))
                    result = QgsLocatorResult()
                    result.filter = self
                    result.displayString = loc['attrs']['title']
                    result.description = loc['attrs']['layer']
                    result.userData = WMSLayerResult(layer=loc['attrs']['layer'], title=loc['attrs']['title'])
                    result.icon = QgsApplication.getThemeIcon("/mActionAddWmsLayer.svg")
                    self.result_found = True
                    self.resultFetched.emit(result)

                elif loc['attrs']['origin'] == 'feature':
                    for key, val in loc['attrs'].items():
                        self.dbg_info('{}: {}'.format(key, val))
                    result = QgsLocatorResult()
                    result.filter = self
                    layer = loc['attrs']['layer']
                    point = QgsPointXY(loc['attrs']['lon'], loc['attrs']['lat'])
                    if layer in self.searchable_layers:
                        layer_display = self.searchable_layers[layer]
                    else:
                        self.info(self.tr('Layer {} is not in the list of searchable layers.'
                                          ' Please report issue.'.format(layer)), Qgis.Warning)
                        layer_display = layer
                    result.group = layer_display
                    result.displayString = loc['attrs']['detail']
                    result.userData = FeatureResult(point=point,
                                                    layer=layer,
                                                    feature_id=loc['attrs']['feature_id'])
                    result.icon = QIcon(":/plugins/swiss_locator/icons/swiss_locator.png")
                    self.result_found = True
                    self.resultFetched.emit(result)

                else:  # locations
                    for key, val in loc['attrs'].items():
                        self.dbg_info('{}: {}'.format(key, val))
                    group_name, group_layer = self.group_info(loc['attrs']['origin'])
                    if 'layerBodId' in loc['attrs']:
                        self.dbg_info("layer: {}".format(loc['attrs']['layerBodId']))
                    if 'featureId' in loc['attrs']:
                        self.dbg_info("feature: {}".format(loc['attrs']['featureId']))

                    result = QgsLocatorResult()
                    result.filter = self
                    result.displayString = strip_tags(loc['attrs']['label'])
                    # result.description = loc['attrs']['detail']
                    # if 'featureId' in loc['attrs']:
                    #     result.description = loc['attrs']['featureId']
                    result.group = group_name
                    result.userData = LocationResult(point=QgsPointXY(loc['attrs']['y'], loc['attrs']['x']),
                                                     bbox=self.box2geometry(loc['attrs']['geom_st_box2d']),
                                                     layer=group_layer,
                                                     feature_id=loc['attrs']['featureId'] if 'featureId' in loc['attrs']
                                                     else None,
                                                     html_label=loc['attrs']['label'])
                    result.icon = QIcon(":/plugins/swiss_locator/icons/swiss_locator.png")
                    self.result_found = True
                    self.resultFetched.emit(result)

        except Exception as e:
            self.info(str(e), Qgis.Critical)
            exc_type, exc_obj, exc_traceback = sys.exc_info()
            filename = os.path.split(exc_traceback.tb_frame.f_code.co_filename)[1]
            self.info('{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical)
            self.info(traceback.print_exception(exc_type, exc_obj, exc_traceback), Qgis.Critical)
    def handle_response(self, response, search: str, feedback: QgsFeedback):
        try:
            if response.status_code != 200:
                if not isinstance(response.exception,
                                  RequestsExceptionUserAbort):
                    self.info(
                        "Error in main response with status code: {} from {}".
                        format(response.status_code, response.url))
                return

            data = json.loads(response.content.decode('utf-8'))
            # self.dbg_info(data)

            if self.is_opendata_swiss_response(data):
                visited_capabilities = []

                for loc in data['result']['results']:
                    display_name = loc['title'].get(self.lang, "")
                    if not display_name:
                        # Fallback to german
                        display_name = loc['title']['de']

                    for res in loc['resources']:

                        url = res['url']
                        url_components = urlparse(url)
                        wms_url = url_components.scheme + '://' + url_components.netloc + '/' + url_components.path + '?'

                        result = QgsLocatorResult()
                        result.filter = self
                        result.group = 'opendata.swiss'
                        result.icon = QgsApplication.getThemeIcon(
                            "/mActionAddWmsLayer.svg")

                        if 'wms' in url.lower():
                            if res['media_type'] == 'WMS':
                                result.displayString = display_name
                                result.description = url

                                if res['title']['de'] == 'GetMap':
                                    layers = parse_qs(
                                        url_components.query)['LAYERS']
                                    result.userData = WMSLayerResult(
                                        layer=layers[0],
                                        title=display_name,
                                        url=wms_url).as_definition()
                                    self.result_found = True
                                    self.resultFetched.emit(result)

                            elif 'request=getcapabilities' in url.lower(
                            ) and url_components.netloc not in visited_capabilities:
                                visited_capabilities.append(
                                    url_components.netloc)

                                def parse_capabilities_result(response):
                                    capabilities = ET.fromstring(
                                        response.content)

                                    # Get xml namespace
                                    match = re.match(r'\{.*\}',
                                                     capabilities.tag)
                                    namespace = match.group(0) if match else ''

                                    # Search for layers containing the search term in the name or title
                                    for layer in capabilities.findall(
                                            './/{}Layer'.format(namespace)):
                                        layername = self.find_text(
                                            layer, '{}Name'.format(namespace))
                                        layertitle = self.find_text(
                                            layer, '{}Title'.format(namespace))
                                        if layername and (
                                                search in layername.lower() or
                                                search in layertitle.lower()):
                                            if not layertitle:
                                                layertitle = layername

                                            result.displayString = layertitle
                                            result.description = '{}?LAYERS={}'.format(
                                                url.replace(
                                                    'GetCapabilities',
                                                    'GetMap'), layername)
                                            result.userData = WMSLayerResult(
                                                layer=layername,
                                                title=layertitle,
                                                url=wms_url).as_definition()
                                            self.result_found = True
                                            self.resultFetched.emit(result)

                                    self.event_loop.quit()

                                # Retrieve Capabilities xml
                                self.event_loop = QEventLoop()
                                nam = NetworkAccessManager()
                                nam.finished.connect(parse_capabilities_result)
                                nam.request(url,
                                            headers=self.HEADERS,
                                            blocking=False)
                                feedback.canceled.connect(self.event_loop.quit)

                                try:
                                    self.event_loop.exec_(
                                        QEventLoop.ExcludeUserInputEvents)
                                except RequestsExceptionUserAbort:
                                    pass
                                except RequestsException as err:
                                    self.info(err)

            else:
                for loc in data['results']:
                    self.dbg_info("keys: {}".format(loc['attrs'].keys()))

                    result = QgsLocatorResult()
                    result.filter = self
                    result.group = 'Swiss Geoportal'
                    if loc['attrs']['origin'] == 'layer':
                        # available keys: ['origin', 'lang', 'layer', 'staging', 'title', 'topics', 'detail', 'label', 'id']
                        for key, val in loc['attrs'].items():
                            self.dbg_info('{}: {}'.format(key, val))
                        result.displayString = loc['attrs']['title']
                        result.description = loc['attrs']['layer']
                        result.userData = WMSLayerResult(
                            layer=loc['attrs']['layer'],
                            title=loc['attrs']['title'],
                            url='http://wms.geo.admin.ch/?VERSION%3D2.0.0'
                        ).as_definition()
                        result.icon = QgsApplication.getThemeIcon(
                            "/mActionAddWmsLayer.svg")
                        self.result_found = True
                        self.resultFetched.emit(result)

                    elif loc['attrs']['origin'] == 'feature':
                        for key, val in loc['attrs'].items():
                            self.dbg_info('{}: {}'.format(key, val))
                        layer = loc['attrs']['layer']
                        point = QgsPointXY(loc['attrs']['lon'],
                                           loc['attrs']['lat'])
                        if layer in self.searchable_layers:
                            layer_display = self.searchable_layers[layer]
                        else:
                            self.info(
                                self.
                                tr('Layer {} is not in the list of searchable layers.'
                                   ' Please report issue.'.format(layer)),
                                Qgis.Warning)
                            layer_display = layer
                        result.group = layer_display
                        result.displayString = loc['attrs']['detail']
                        result.userData = FeatureResult(
                            point=point,
                            layer=layer,
                            feature_id=loc['attrs']
                            ['feature_id']).as_definition()
                        result.icon = QIcon(
                            ":/plugins/swiss_locator/icons/swiss_locator.png")
                        self.result_found = True
                        self.resultFetched.emit(result)

                    else:  # locations
                        for key, val in loc['attrs'].items():
                            self.dbg_info('{}: {}'.format(key, val))
                        group_name, group_layer = self.group_info(
                            loc['attrs']['origin'])
                        if 'layerBodId' in loc['attrs']:
                            self.dbg_info("layer: {}".format(
                                loc['attrs']['layerBodId']))
                        if 'featureId' in loc['attrs']:
                            self.dbg_info("feature: {}".format(
                                loc['attrs']['featureId']))

                        result.displayString = strip_tags(
                            loc['attrs']['label'])
                        # result.description = loc['attrs']['detail']
                        # if 'featureId' in loc['attrs']:
                        #     result.description = loc['attrs']['featureId']
                        result.group = group_name
                        result.userData = LocationResult(
                            point=QgsPointXY(loc['attrs']['y'],
                                             loc['attrs']['x']),
                            bbox=self.box2geometry(
                                loc['attrs']['geom_st_box2d']),
                            layer=group_layer,
                            feature_id=loc['attrs']['featureId']
                            if 'featureId' in loc['attrs'] else None,
                            html_label=loc['attrs']['label']).as_definition()
                        result.icon = QIcon(
                            ":/plugins/swiss_locator/icons/swiss_locator.png")
                        self.result_found = True
                        self.resultFetched.emit(result)

        except Exception as e:
            self.info(str(e), Qgis.Critical)
            exc_type, exc_obj, exc_traceback = sys.exc_info()
            filename = os.path.split(
                exc_traceback.tb_frame.f_code.co_filename)[1]
            self.info(
                '{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno),
                Qgis.Critical)
            self.info(
                traceback.print_exception(exc_type, exc_obj, exc_traceback),
                Qgis.Critical)
Ejemplo n.º 22
0
    def handle_response(self, response, search_text: str):
        try:
            if response.status_code != 200:
                if not isinstance(response.exception,
                                  RequestsExceptionUserAbort):
                    self.info("Error in main response with status code: "
                              "{} from {}".format(response.status_code,
                                                  response.url))
                return

            data = json.loads(response.content.decode('utf-8'))

            # Since results are ordered by score (0 to 1)
            # we use an ordering score to keep the same order than the one from the remote service
            score = 1

            # sub-filtering
            # dbg_info(data['result_counts'])
            if len(data['result_counts']) > 1:
                for _filter in data['result_counts']:
                    result = QgsLocatorResult()
                    result.filter = self
                    result.group = 'Suche verfeinern'
                    result.displayString = _filter['filterword']
                    if _filter['count']:
                        result.displayString += ' ({})'.format(
                            _filter['count'])
                    self.dbg_info(_filter)
                    result.icon, _ = dataproduct2icon_description(
                        _filter['dataproduct_id'], 'datasetview')
                    result.userData = FilterResult(_filter['filterword'],
                                                   search_text)
                    result.score = score
                    self.resultFetched.emit(result)
                    score -= 0.001

            for res in data['results']:
                # dbg_info(res)

                result = QgsLocatorResult()
                result.filter = self

                if 'feature' in res.keys():
                    f = res['feature']
                    # dbg_info("feature: {}".format(f))
                    result.displayString = f['display']
                    result.group = 'Orte'
                    result.userData = FeatureResult(
                        dataproduct_id=f['dataproduct_id'],
                        id_field_name=f['id_field_name'],
                        id_field_type=f['id_field_type'],
                        feature_id=f['feature_id'])
                    data_product = f['dataproduct_id']
                    data_type = None
                    result.icon, result.description = dataproduct2icon_description(
                        data_product, data_type)
                    result.score = score
                    self.resultFetched.emit(result)
                    score -= 0.001

                elif 'dataproduct' in res.keys():
                    dp = res['dataproduct']
                    # self.dbg_info("data_product: {}".format(dp))
                    result = self.data_product_qgsresult(
                        dp, False, score, dp['stacktype'])
                    self.resultFetched.emit(result)
                    score -= 0.001

                    # also give sublayers
                    for layer in dp.get('sublayers', []):
                        always_show_sublayers = True
                        if always_show_sublayers or search_text.lower(
                        ) in layer['display'].lower():
                            result = self.data_product_qgsresult(
                                layer, True, score, dp['stacktype'])
                            self.resultFetched.emit(result)
                            score -= 0.001

                else:
                    continue

                self.result_found = True

        except Exception as e:
            self.info(str(e), Qgis.Critical)
            exc_type, exc_obj, exc_traceback = sys.exc_info()
            filename = os.path.split(
                exc_traceback.tb_frame.f_code.co_filename)[1]
            self.info(
                '{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno),
                Qgis.Critical)
            self.info(
                traceback.print_exception(exc_type, exc_obj, exc_traceback),
                Qgis.Critical)