From 8ddd960505308fc829ba17029b6917814f257b65 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 19 Oct 2021 11:18:22 +0200 Subject: Add the btscanner example Pick-to: 6.2 Task-number: PYSIDE-841 Task-number: PYSIDE-1690 Change-Id: I6b3d774b4c136af2b71251e0b8aafa6f12ba39a2 Reviewed-by: Cristian Maureira-Fredes --- examples/bluetooth/btscanner/btscanner.pyproject | 3 + examples/bluetooth/btscanner/device.py | 166 +++++++++++++++++++++++ examples/bluetooth/btscanner/device.ui | 111 +++++++++++++++ examples/bluetooth/btscanner/doc/btscanner.rst | 4 + examples/bluetooth/btscanner/main.py | 55 ++++++++ examples/bluetooth/btscanner/service.py | 85 ++++++++++++ examples/bluetooth/btscanner/service.ui | 71 ++++++++++ examples/bluetooth/btscanner/ui_device.py | 89 ++++++++++++ examples/bluetooth/btscanner/ui_service.py | 56 ++++++++ 9 files changed, 640 insertions(+) create mode 100644 examples/bluetooth/btscanner/btscanner.pyproject create mode 100644 examples/bluetooth/btscanner/device.py create mode 100644 examples/bluetooth/btscanner/device.ui create mode 100644 examples/bluetooth/btscanner/doc/btscanner.rst create mode 100644 examples/bluetooth/btscanner/main.py create mode 100644 examples/bluetooth/btscanner/service.py create mode 100644 examples/bluetooth/btscanner/service.ui create mode 100644 examples/bluetooth/btscanner/ui_device.py create mode 100644 examples/bluetooth/btscanner/ui_service.py (limited to 'examples') diff --git a/examples/bluetooth/btscanner/btscanner.pyproject b/examples/bluetooth/btscanner/btscanner.pyproject new file mode 100644 index 000000000..208487fe7 --- /dev/null +++ b/examples/bluetooth/btscanner/btscanner.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "device.py", "service.py", "device.ui", "service.ui"] +} diff --git a/examples/bluetooth/btscanner/device.py b/examples/bluetooth/btscanner/device.py new file mode 100644 index 000000000..ba221b155 --- /dev/null +++ b/examples/bluetooth/btscanner/device.py @@ -0,0 +1,166 @@ +############################################################################# +## +## Copyright (C) 2021 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +from PySide6.QtCore import QPoint, Qt, Slot +from PySide6.QtGui import QColor +from PySide6.QtWidgets import QDialog, QListWidgetItem, QListWidget, QMenu +from PySide6.QtBluetooth import (QBluetoothAddress, QBluetoothDeviceDiscoveryAgent, + QBluetoothDeviceInfo, QBluetoothLocalDevice) + +from ui_device import Ui_DeviceDiscovery +from service import ServiceDiscoveryDialog + + +class DeviceDiscoveryDialog(QDialog): + def __init__(self, parent=None): + super().__init__(parent) + self._local_device = QBluetoothLocalDevice() + self._ui = Ui_DeviceDiscovery() + self._ui.setupUi(self) + # In case of multiple Bluetooth adapters it is possible to set adapter + # which will be used. Example code: + # + # address = QBluetoothAddress("XX:XX:XX:XX:XX:XX") + # discoveryAgent = QBluetoothDeviceDiscoveryAgent(address) + + self._discovery_agent = QBluetoothDeviceDiscoveryAgent() + + self._ui.scan.clicked.connect(self.start_scan) + self._discovery_agent.deviceDiscovered.connect(self.add_device) + self._discovery_agent.finished.connect(self.scan_finished) + self._ui.list.itemActivated.connect(self.item_activated) + self._local_device.hostModeStateChanged.connect(self.host_mode_state_changed) + + self.host_mode_state_changed(self._local_device.hostMode()) + # add context menu for devices to be able to pair device + self._ui.list.setContextMenuPolicy(Qt.CustomContextMenu) + self._ui.list.customContextMenuRequested.connect(self.display_pairing_menu) + self._local_device.pairingFinished.connect(self.pairing_done) + + @Slot(QBluetoothDeviceInfo) + def add_device(self, info): + a = info.address().toString() + label = f"{a} {info.name()}" + items = self._ui.list.findItems(label, Qt.MatchExactly) + if not items: + item = QListWidgetItem(label) + pairing_status = self._local_device.pairingStatus(info.address()) + if (pairing_status == QBluetoothLocalDevice.Paired + or pairing_status == QBluetoothLocalDevice.AuthorizedPaired): + item.setForeground(QColor(Qt.green)) + else: + item.setForeground(QColor(Qt.black)) + self._ui.list.addItem(item) + + @Slot() + def start_scan(self): + self._discovery_agent.start() + self._ui.scan.setEnabled(False) + + @Slot() + def scan_finished(self): + self._ui.scan.setEnabled(True) + + @Slot(QListWidgetItem) + def item_activated(self, item): + text = item.text() + index = text.find(' ') + if index == -1: + return + + address = QBluetoothAddress(text[0:index]) + name = text[index + 1:] + + d = ServiceDiscoveryDialog(name, address) + d.exec() + + @Slot(bool) + def on_discoverable_clicked(self, clicked): + if clicked: + self._local_device.setHostMode(QBluetoothLocalDevice.HostDiscoverable) + else: + self._local_device.setHostMode(QBluetoothLocalDevice.HostConnectable) + + @Slot(bool) + def on_power_clicked(self, clicked): + if clicked: + self._local_device.powerOn() + else: + self._local_device.setHostMode(QBluetoothLocalDevice.HostPoweredOff) + + @Slot(QBluetoothLocalDevice.HostMode) + def host_mode_state_changed(self, mode): + self._ui.power.setChecked(mode != QBluetoothLocalDevice.HostPoweredOff) + self._ui.discoverable.setChecked(mode == QBluetoothLocalDevice.HostDiscoverable) + + on = mode != QBluetoothLocalDevice.HostPoweredOff + self._ui.scan.setEnabled(on) + self._ui.discoverable.setEnabled(on) + + @Slot(QPoint) + def display_pairing_menu(self, pos): + if self._ui.list.count() == 0: + return + menu = QMenu(self) + pair_action = menu.addAction("Pair") + remove_pair_action = menu.addAction("Remove Pairing") + chosen_action = menu.exec(self._ui.list.viewport().mapToGlobal(pos)) + current_item = self._ui.list.currentItem() + + text = current_item.text() + index = text.find(' ') + if index == -1: + return + + address = QBluetoothAddress(text[0:index]) + if chosen_action == pair_action: + self._local_device.requestPairing(address, QBluetoothLocalDevice.Paired) + elif chosen_action == remove_pair_action: + self._local_device.requestPairing(address, QBluetoothLocalDevice.Unpaired) + + @Slot(QBluetoothAddress, QBluetoothLocalDevice.Pairing) + def pairing_done(self, address, pairing): + items = self._ui.list.findItems(address.toString(), Qt.MatchContains) + + color = QColor(Qt.red) + if pairing == QBluetoothLocalDevice.Paired or pairing == QBluetoothLocalDevice.AuthorizedPaired: + color = QColor(Qt.green) + for item in items: + item.setForeground(color) diff --git a/examples/bluetooth/btscanner/device.ui b/examples/bluetooth/btscanner/device.ui new file mode 100644 index 000000000..fa81c5cb4 --- /dev/null +++ b/examples/bluetooth/btscanner/device.ui @@ -0,0 +1,111 @@ + + + DeviceDiscovery + + + + 0 + 0 + 400 + 411 + + + + Bluetooth Scanner + + + + + + + + + Local Device + + + + + + Bluetooth Powered On + + + true + + + + + + + Discoverable + + + true + + + + + + + + + + + + Scan + + + + + + + Clear + + + + + + + Quit + + + + + + + + + + + quit + clicked() + DeviceDiscovery + accept() + + + 323 + 275 + + + 396 + 268 + + + + + clear + clicked() + list + clear() + + + 188 + 276 + + + 209 + 172 + + + + + diff --git a/examples/bluetooth/btscanner/doc/btscanner.rst b/examples/bluetooth/btscanner/doc/btscanner.rst new file mode 100644 index 000000000..d99af3be5 --- /dev/null +++ b/examples/bluetooth/btscanner/doc/btscanner.rst @@ -0,0 +1,4 @@ +Bluetooth Scanner Example +========================= + +An example showing how to locate Bluetooth devices. diff --git a/examples/bluetooth/btscanner/main.py b/examples/bluetooth/btscanner/main.py new file mode 100644 index 000000000..ff364f55e --- /dev/null +++ b/examples/bluetooth/btscanner/main.py @@ -0,0 +1,55 @@ +############################################################################# +## +## Copyright (C) 2021 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +"""PySide6 port of the bluetooth/btscanner example from Qt v6.x""" + +import sys + +from PySide6.QtCore import Qt +from PySide6.QtWidgets import QApplication, QWidget + +from device import DeviceDiscoveryDialog + + +if __name__ == '__main__': + app = QApplication(sys.argv) + d = DeviceDiscoveryDialog() + d.exec() + sys.exit(0) diff --git a/examples/bluetooth/btscanner/service.py b/examples/bluetooth/btscanner/service.py new file mode 100644 index 000000000..e3916082e --- /dev/null +++ b/examples/bluetooth/btscanner/service.py @@ -0,0 +1,85 @@ +############################################################################# +## +## Copyright (C) 2021 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +from PySide6.QtCore import Qt, Slot +from PySide6.QtWidgets import QDialog +from PySide6.QtBluetooth import (QBluetoothAddress, QBluetoothServiceInfo, + QBluetoothServiceDiscoveryAgent, QBluetoothLocalDevice) + +from ui_service import Ui_ServiceDiscovery + + +class ServiceDiscoveryDialog(QDialog): + def __init__(self, name, address, parent=None): + super().__init__(parent) + self._ui = Ui_ServiceDiscovery() + self._ui.setupUi(self) + + # Using default Bluetooth adapter + local_device = QBluetoothLocalDevice() + adapter_address = QBluetoothAddress(local_device.address()) + + # In case of multiple Bluetooth adapters it is possible to + # set which adapter will be used by providing MAC Address. + # Example code: + # + # adapterAddress = QBluetoothAddress("XX:XX:XX:XX:XX:XX") + # discoveryAgent = QBluetoothServiceDiscoveryAgent(adapterAddress) + + self._discovery_agent = QBluetoothServiceDiscoveryAgent(adapter_address) + self._discovery_agent.setRemoteAddress(address) + + self.setWindowTitle(name) + + self._discovery_agent.serviceDiscovered.connect(self.add_service) + self._discovery_agent.finished.connect(self._ui.status.hide) + self._discovery_agent.start() + + @Slot(QBluetoothServiceInfo) + def add_service(self, info): + line = info.serviceName() + if not line: + return + + if info.serviceDescription(): + line += "\n\t" + info.serviceDescription() + if info.serviceProvider(): + line += "\n\t" + info.serviceProvider() + self._ui.list.addItem(line) diff --git a/examples/bluetooth/btscanner/service.ui b/examples/bluetooth/btscanner/service.ui new file mode 100644 index 000000000..4ca12ee05 --- /dev/null +++ b/examples/bluetooth/btscanner/service.ui @@ -0,0 +1,71 @@ + + + ServiceDiscovery + + + + 0 + 0 + 539 + 486 + + + + Available Services + + + + + + + + + Querying... + + + + + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + ServiceDiscovery + accept() + + + 396 + 457 + + + 535 + 443 + + + + + buttonBox + rejected() + ServiceDiscovery + reject() + + + 339 + 464 + + + 535 + 368 + + + + + diff --git a/examples/bluetooth/btscanner/ui_device.py b/examples/bluetooth/btscanner/ui_device.py new file mode 100644 index 000000000..f351854d7 --- /dev/null +++ b/examples/bluetooth/btscanner/ui_device.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'device.ui' +## +## Created by: Qt User Interface Compiler version 6.2.0 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QApplication, QCheckBox, QDialog, QGroupBox, + QHBoxLayout, QListWidget, QListWidgetItem, QPushButton, + QSizePolicy, QVBoxLayout) + +class Ui_DeviceDiscovery(object): + def setupUi(self, DeviceDiscovery): + if not DeviceDiscovery.objectName(): + DeviceDiscovery.setObjectName(u"DeviceDiscovery") + DeviceDiscovery.resize(400, 411) + self.verticalLayout = QVBoxLayout(DeviceDiscovery) + self.verticalLayout.setObjectName(u"verticalLayout") + self.list = QListWidget(DeviceDiscovery) + self.list.setObjectName(u"list") + + self.verticalLayout.addWidget(self.list) + + self.groupBox = QGroupBox(DeviceDiscovery) + self.groupBox.setObjectName(u"groupBox") + self.horizontalLayout_2 = QHBoxLayout(self.groupBox) + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.power = QCheckBox(self.groupBox) + self.power.setObjectName(u"power") + self.power.setChecked(True) + + self.horizontalLayout_2.addWidget(self.power) + + self.discoverable = QCheckBox(self.groupBox) + self.discoverable.setObjectName(u"discoverable") + self.discoverable.setChecked(True) + + self.horizontalLayout_2.addWidget(self.discoverable) + + + self.verticalLayout.addWidget(self.groupBox) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.scan = QPushButton(DeviceDiscovery) + self.scan.setObjectName(u"scan") + + self.horizontalLayout.addWidget(self.scan) + + self.clear = QPushButton(DeviceDiscovery) + self.clear.setObjectName(u"clear") + + self.horizontalLayout.addWidget(self.clear) + + self.quit = QPushButton(DeviceDiscovery) + self.quit.setObjectName(u"quit") + + self.horizontalLayout.addWidget(self.quit) + + + self.verticalLayout.addLayout(self.horizontalLayout) + + + self.retranslateUi(DeviceDiscovery) + self.quit.clicked.connect(DeviceDiscovery.accept) + self.clear.clicked.connect(self.list.clear) + + QMetaObject.connectSlotsByName(DeviceDiscovery) + # setupUi + + def retranslateUi(self, DeviceDiscovery): + DeviceDiscovery.setWindowTitle(QCoreApplication.translate("DeviceDiscovery", u"Bluetooth Scanner", None)) + self.groupBox.setTitle(QCoreApplication.translate("DeviceDiscovery", u"Local Device", None)) + self.power.setText(QCoreApplication.translate("DeviceDiscovery", u"Bluetooth Powered On", None)) + self.discoverable.setText(QCoreApplication.translate("DeviceDiscovery", u"Discoverable", None)) + self.scan.setText(QCoreApplication.translate("DeviceDiscovery", u"Scan", None)) + self.clear.setText(QCoreApplication.translate("DeviceDiscovery", u"Clear", None)) + self.quit.setText(QCoreApplication.translate("DeviceDiscovery", u"Quit", None)) + # retranslateUi diff --git a/examples/bluetooth/btscanner/ui_service.py b/examples/bluetooth/btscanner/ui_service.py new file mode 100644 index 000000000..c5a37a933 --- /dev/null +++ b/examples/bluetooth/btscanner/ui_service.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'service.ui' +## +## Created by: Qt User Interface Compiler version 6.2.1 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox, + QLabel, QListWidget, QListWidgetItem, QSizePolicy, + QVBoxLayout) + +class Ui_ServiceDiscovery(object): + def setupUi(self, ServiceDiscovery): + if not ServiceDiscovery.objectName(): + ServiceDiscovery.setObjectName(u"ServiceDiscovery") + ServiceDiscovery.resize(539, 486) + self.verticalLayout = QVBoxLayout(ServiceDiscovery) + self.verticalLayout.setObjectName(u"verticalLayout") + self.list = QListWidget(ServiceDiscovery) + self.list.setObjectName(u"list") + + self.verticalLayout.addWidget(self.list) + + self.status = QLabel(ServiceDiscovery) + self.status.setObjectName(u"status") + + self.verticalLayout.addWidget(self.status) + + self.buttonBox = QDialogButtonBox(ServiceDiscovery) + self.buttonBox.setObjectName(u"buttonBox") + self.buttonBox.setStandardButtons(QDialogButtonBox.Close) + + self.verticalLayout.addWidget(self.buttonBox) + + + self.retranslateUi(ServiceDiscovery) + self.buttonBox.accepted.connect(ServiceDiscovery.accept) + self.buttonBox.rejected.connect(ServiceDiscovery.reject) + + QMetaObject.connectSlotsByName(ServiceDiscovery) + # setupUi + + def retranslateUi(self, ServiceDiscovery): + ServiceDiscovery.setWindowTitle(QCoreApplication.translate("ServiceDiscovery", u"Available Services", None)) + self.status.setText(QCoreApplication.translate("ServiceDiscovery", u"Querying...", None)) + # retranslateUi -- cgit v1.2.3