Files
purple-electrumwallet/electrum/gui/qt/qrtextedit.py
T
SomberNight c1dbcab9bb qt: new qrreader using QtMultimedia; drop CalinsQRReader(mac)
This commit ports the work of EchterAgo and cculianu from Electron-Cash,
to implement a new toolchain to scan qr codes.

Previously, on Linux and Win, we have been using zbar to access the camera
and read qrcodes; and on macOS we used CalinsQRReader (an objective-C
project by cculianu).

The new toolchain added here can use QtMultimedia to access the camera,
and then feed that image into zbar. When used this way, zbar needs
fewer dependencies and is easier to compile, in particular it can be
compiled for macOS.

The new toolchain works on all three platforms, with some caveats
(see code comments in related commits) -- so we also keep the end-to-end
zbar toolchain; but at least we can drop CalinsQRReader.

The related changes in Electron-Cash are spread over 50+ commits (several PRs and direct
pushes to master), but see in particular:
https://github.com/Electron-Cash/Electron-Cash/pull/1376

some other interesting links:
https://github.com/Electron-Cash/Electron-Cash/commit/b2b737001c8cc41a38fa580ea252a6d24e08f5d5
https://github.com/Electron-Cash/Electron-Cash/commit/163224cf1fad3af63f2d3cbe68a34fb8ff279af6
https://github.com/Electron-Cash/Electron-Cash/commit/3b31e0fcb13f67646228ff42c0dd39d2a0912291
https://github.com/Electron-Cash/Electron-Cash/commit/eda015908e9d6ea9a0adfbda9db55b929c0926ba
https://github.com/Electron-Cash/Electron-Cash/pull/1545
https://github.com/Electron-Cash/Electron-Cash/commit/052aa06c23b939adcea07c701f70ae28ebcf9e0a
2021-06-25 16:51:58 +02:00

123 lines
4.2 KiB
Python

from PyQt5.QtWidgets import QFileDialog
from electrum.i18n import _
from electrum.plugin import run_hook
from electrum.simple_config import SimpleConfig
from electrum.util import UserFacingException
from electrum.logging import Logger
from .util import ButtonsTextEdit, MessageBoxMixin, ColorScheme, getOpenFileName
class ShowQRTextEdit(ButtonsTextEdit):
def __init__(self, text=None, *, config: SimpleConfig):
ButtonsTextEdit.__init__(self, text)
self.config = config
self.setReadOnly(True)
icon = "qrcode_white.png" if ColorScheme.dark_scheme else "qrcode.png"
self.addButton(icon, self.qr_show, _("Show as QR code"))
run_hook('show_text_edit', self)
def qr_show(self):
from .qrcodewidget import QRDialog
try:
s = str(self.toPlainText())
except:
s = self.toPlainText()
QRDialog(
data=s,
parent=self,
config=self.config,
).exec_()
def contextMenuEvent(self, e):
m = self.createStandardContextMenu()
m.addAction(_("Show as QR code"), self.qr_show)
m.exec_(e.globalPos())
class ScanQRTextEdit(ButtonsTextEdit, MessageBoxMixin, Logger):
def __init__(self, text="", allow_multi=False, *, config: SimpleConfig):
ButtonsTextEdit.__init__(self, text)
Logger.__init__(self)
self.allow_multi = allow_multi
self.config = config
self.setReadOnly(False)
self.addButton("file.png", self.file_input, _("Read file"))
icon = "camera_white.png" if ColorScheme.dark_scheme else "camera_dark.png"
self.addButton(icon, self.qr_input, _("Read QR code"))
run_hook('scan_text_edit', self)
def file_input(self):
fileName = getOpenFileName(
parent=self,
title='select file',
config=self.config,
)
if not fileName:
return
try:
try:
with open(fileName, "r") as f:
data = f.read()
except UnicodeError as e:
with open(fileName, "rb") as f:
data = f.read()
data = data.hex()
except BaseException as e:
self.show_error(_('Error opening file') + ':\n' + repr(e))
else:
self.setText(data)
# Due to the asynchronous nature of the qr reader we need to keep the
# dialog instance as member variable to prevent reentrancy/multiple ones
# from being presented at once.
qr_dialog = None
def qr_input(self, *, callback=None) -> None:
if self.qr_dialog:
self.logger.warning("QR dialog is already presented, ignoring.")
return
from . import ElectrumGui
if ElectrumGui.warn_if_cant_import_qrreader(self):
return
from .qrreader import QrReaderCameraDialog, CameraError, MissingQrDetectionLib
try:
self.qr_dialog = QrReaderCameraDialog(parent=self.top_level_window(), config=self.config)
def _on_qr_reader_finished(success: bool, error: str, data):
if self.qr_dialog:
self.qr_dialog.deleteLater()
self.qr_dialog = None
if not success:
if error:
self.show_error(error)
return
if not data:
data = ''
if self.allow_multi:
new_text = self.text() + data + '\n'
else:
new_text = data
self.setText(new_text)
if callback and success:
callback(data)
self.qr_dialog.qr_finished.connect(_on_qr_reader_finished)
self.qr_dialog.start_scan(self.config.get_video_device())
except (MissingQrDetectionLib, CameraError) as e:
self.qr_dialog = None
self.show_error(str(e))
except Exception as e:
self.logger.exception('camera error')
self.qr_dialog = None
self.show_error(repr(e))
def contextMenuEvent(self, e):
m = self.createStandardContextMenu()
m.addAction(_("Read QR code"), self.qr_input)
m.exec_(e.globalPos())